summaryrefslogtreecommitdiff
path: root/src/main/scala/Chisel
diff options
context:
space:
mode:
authorJim Lawson2015-05-11 10:04:01 -0700
committerJim Lawson2015-07-24 15:50:53 -0700
commitb208bfb5691c7b5921dd47d0b599726872acd1cd (patch)
tree5d8695f13db41a807622dfdc93c1b6841911acc8 /src/main/scala/Chisel
parentcaa7602b878c03c47fd263550e37715f1a67f854 (diff)
move source files under Chisel folder - eclipse compatibility
Diffstat (limited to 'src/main/scala/Chisel')
-rw-r--r--src/main/scala/Chisel/Backend.scala10
-rw-r--r--src/main/scala/Chisel/Core.scala1248
-rw-r--r--src/main/scala/Chisel/Driver.scala420
-rw-r--r--src/main/scala/Chisel/Enum.scala44
-rw-r--r--src/main/scala/Chisel/Error.scala167
-rw-r--r--src/main/scala/Chisel/FP.scala321
-rw-r--r--src/main/scala/Chisel/JHFormat.scala105
-rw-r--r--src/main/scala/Chisel/Literal.scala199
-rw-r--r--src/main/scala/Chisel/Parameters.scala644
-rw-r--r--src/main/scala/Chisel/Params.scala195
-rw-r--r--src/main/scala/Chisel/Tester.scala417
-rw-r--r--src/main/scala/Chisel/utils.scala561
12 files changed, 4331 insertions, 0 deletions
diff --git a/src/main/scala/Chisel/Backend.scala b/src/main/scala/Chisel/Backend.scala
new file mode 100644
index 00000000..9b8bfb6d
--- /dev/null
+++ b/src/main/scala/Chisel/Backend.scala
@@ -0,0 +1,10 @@
+package Chisel
+import Chisel._
+
+class Backend;
+class FloBackend extends Backend;
+class CppBackend extends Backend;
+class VerilogBackend extends Backend;
+class FPGABackend extends Backend;
+class DotBackend extends Backend;
+class SysCBackend extends Backend;
diff --git a/src/main/scala/Chisel/Core.scala b/src/main/scala/Chisel/Core.scala
new file mode 100644
index 00000000..8236c154
--- /dev/null
+++ b/src/main/scala/Chisel/Core.scala
@@ -0,0 +1,1248 @@
+package Chisel
+import scala.collection.mutable.{ArrayBuffer, Stack, HashSet, HashMap, LinkedHashMap}
+import java.lang.reflect.Modifier._
+import java.lang.Double.longBitsToDouble
+import java.lang.Float.intBitsToFloat
+
+class GenSym {
+ private var counter = -1
+ def nextInt: Int = {
+ counter += 1
+ counter
+ }
+ def next(name: String): String =
+ name + "_" + nextInt
+}
+
+object Builder {
+ val components = new ArrayBuffer[Component]()
+ val genSym = new GenSym()
+ val scopes = new Stack[HashSet[String]]()
+ def scope = scopes.top
+ val switchKeyz = new Stack[Stack[Bits]]()
+ def switchKeys = switchKeyz.top
+ def pushScope = {
+ scopes.push(new HashSet[String]())
+ switchKeyz.push(new Stack[Bits]())
+ }
+ def popScope = {
+ scopes.pop()
+ switchKeyz.pop()
+ }
+ val modules = new HashMap[String,Module]()
+ def addModule(mod: Module) {
+ modules(mod.cid) = mod
+ }
+ val modulez = new Stack[Module]()
+ def pushModule(mod: Module) {
+ modulez.push(mod)
+ }
+ def getComponent(): Module = if (modulez.length > 0) modulez.head else null
+ def popModule() {
+ modulez.pop
+ }
+ val componentNames = new HashSet[String]()
+ def UniqueComponent(name: String, ports: Array[Port], body: Command) = {
+ val res = Component(if (componentNames.contains(name)) genSym.next(name) else name, ports, body)
+ componentNames += name
+ res
+ }
+ val commandz = new Stack[ArrayBuffer[Command]]()
+ def commands = commandz.top
+ def pushCommand(cmd: Command) = commands += cmd
+ def commandify(cmds: ArrayBuffer[Command]): Command = {
+ if (cmds.length == 0)
+ EmptyCommand()
+ else if (cmds.length == 1)
+ cmds(0)
+ else
+ Begin(cmds.toList)
+ }
+ def pushCommands =
+ commandz.push(new ArrayBuffer[Command]())
+ def popCommands: Command = {
+ val newCommands = commands
+ commandz.pop()
+ commandify(newCommands)
+ }
+ def collectCommands[T <: Module](f: => T): (Command, T) = {
+ pushCommands
+ val mod = f
+ // mod.setRefs
+ (popCommands, mod)
+ }
+
+ private val refmap = new HashMap[String,Immediate]()
+
+ def legalizeName (name: String) = {
+ if (name == "mem" || name == "node" || name == "wire" ||
+ name == "reg" || name == "inst")
+ // genSym.next(name)
+ name + "__"
+ else
+ name
+ }
+
+ def setRefForId(id: String, name: String, overwrite: Boolean = false) {
+ if (overwrite || !refmap.contains(id)) {
+ refmap(id) = Ref(legalizeName(name))
+ }
+ }
+
+ def setFieldForId(parentid: String, id: String, name: String) {
+ refmap(id) = Slot(Alias(parentid), legalizeName(name))
+ }
+
+ def setIndexForId(parentid: String, id: String, index: Int) {
+ refmap(id) = Index(Alias(parentid), index)
+ }
+
+ def getRefForId(id: String): Immediate = {
+ if (refmap.contains(id)) {
+ refmap(id)
+ } else {
+ val ref = Ref(genSym.next("T"))
+ refmap(id) = ref
+ ref
+ }
+ }
+
+ def build[T <: Module](f: => T): (Circuit, T) = {
+ val (cmd, mod) = collectCommands(f)
+ setRefForId(mod.cid, mod.name)
+ (Circuit(components.toArray, components.last.name), mod)
+ }
+
+}
+
+import Builder._
+
+/// CHISEL IR
+
+case class PrimOp(val name: String) {
+ override def toString = name
+}
+
+object PrimOp {
+ val AddOp = PrimOp("add")
+ val AddModOp = PrimOp("add-wrap")
+ val SubOp = PrimOp("sub")
+ val SubModOp = PrimOp("sub-wrap")
+ val TimesOp = PrimOp("mul")
+ val DivideOp = PrimOp("div")
+ val ModOp = PrimOp("mod")
+ val ShiftLeftOp = PrimOp("shl")
+ val ShiftRightOp = PrimOp("shr")
+ val DynamicShiftLeftOp = PrimOp("dshl")
+ val DynamicShiftRightOp = PrimOp("dshr")
+ val BitAndOp = PrimOp("bit-and")
+ val BitOrOp = PrimOp("bit-or")
+ val BitXorOp = PrimOp("bit-xor")
+ val BitNotOp = PrimOp("bit-not")
+ val ConcatOp = PrimOp("cat")
+ val BitSelectOp = PrimOp("bit")
+ val BitsExtractOp = PrimOp("bits")
+ val LessOp = PrimOp("lt")
+ val LessEqOp = PrimOp("leq")
+ val GreaterOp = PrimOp("gt")
+ val GreaterEqOp = PrimOp("geq")
+ val EqualOp = PrimOp("eq")
+ val PatternEqualOp = PrimOp("pattern-equal")
+ val PadOp = PrimOp("pad")
+ val NotEqualOp = PrimOp("neq")
+ val NegOp = PrimOp("neg")
+ val MultiplexOp = PrimOp("mux")
+ val XorReduceOp = PrimOp("xorr")
+ val ConvertOp = PrimOp("convert")
+ val AsUIntOp = PrimOp("as-UInt")
+ val AsSIntOp = PrimOp("as-SInt")
+}
+import PrimOp._
+
+abstract class Immediate {
+ def fullname: String
+ def name: String
+ def debugName = fullname
+}
+
+abstract class Arg extends Immediate {
+ def fullname: String
+ def name: String
+}
+
+case class Alias(val id: String) extends Arg {
+ def fullname = getRefForId(id).fullname
+ def name = getRefForId(id).name
+ override def debugName = getRefForId(id).debugName
+ def emit: String = "Alias(" + id + ")"
+}
+
+abstract class LitArg (val num: BigInt, val width: Int) extends Arg {
+}
+
+case class ULit(n: BigInt, w: Int = -1) extends LitArg(n, w) {
+ def fullname = name
+ def name = "UInt<" + width + ">(" + num + ")"
+}
+
+case class SLit(n: BigInt, w: Int = -1) extends LitArg(n, w) {
+ def fullname = name
+ def name = "SInt<" + width + ">(" + num + ")"
+}
+
+case class Ref(val name: String) extends Immediate {
+ def fullname = name
+}
+case class Slot(val imm: Immediate, val name: String) extends Immediate {
+ def fullname = {
+ val imm_fullname = imm.fullname
+ if (imm_fullname == "this") name else imm_fullname + "." + name
+ }
+ override def debugName = {
+ val imm_debugName = imm.debugName
+ if (imm_debugName == "this") name else imm_debugName + "." + name
+ }
+}
+case class Index(val imm: Immediate, val value: Int) extends Immediate {
+ def name = "[" + value + "]"
+ def fullname = imm.fullname + "[" + value + "]"
+ override def debugName = imm.debugName + "." + value
+}
+
+case class Port(val id: String, val dir: Direction, val kind: Kind);
+
+abstract class Width;
+case class UnknownWidth() extends Width;
+case class IntWidth(val value: Int) extends Width;
+
+abstract class Kind(val isFlip: Boolean);
+case class UnknownType(flip: Boolean) extends Kind(flip);
+case class UIntType(val width: Width, flip: Boolean) extends Kind(flip);
+case class SIntType(val width: Width, flip: Boolean) extends Kind(flip);
+case class FloType(flip: Boolean) extends Kind(flip);
+case class DblType(flip: Boolean) extends Kind(flip);
+case class BundleType(val ports: Array[Port], flip: Boolean) extends Kind(flip);
+case class VectorType(val size: Int, val kind: Kind, flip: Boolean) extends Kind(flip);
+
+abstract class Command;
+abstract class Definition extends Command {
+ def id: String
+ def name = getRefForId(id).name
+}
+case class DefUInt(val id: String, val value: BigInt, val width: Int) extends Definition;
+case class DefSInt(val id: String, val value: BigInt, val width: Int) extends Definition;
+case class DefFlo(val id: String, val value: Float) extends Definition;
+case class DefDbl(val id: String, val value: Double) extends Definition;
+case class DefPrim(val id: String, val kind: Kind, val op: PrimOp, val args: Array[Arg], val lits: Array[BigInt]) extends Definition;
+case class DefWire(val id: String, val kind: Kind) extends Definition;
+case class DefRegister(val id: String, val kind: Kind) extends Definition;
+case class DefMemory(val id: String, val kind: Kind, val size: Int) extends Definition;
+case class DefSeqMemory(val id: String, val kind: Kind, val size: Int) extends Definition;
+case class DefAccessor(val id: String, val source: Alias, val direction: Direction, val index: Arg) extends Definition;
+case class DefInstance(val id: String, val module: String) extends Definition;
+case class Conditionally(val prep: Command, val pred: Arg, val conseq: Command, var alt: Command) extends Command;
+case class Begin(val body: List[Command]) extends Command();
+case class Connect(val loc: Alias, val exp: Arg) extends Command;
+case class BulkConnect(val loc1: Alias, val loc2: Alias) extends Command;
+case class ConnectInit(val loc: Alias, val exp: Arg) extends Command;
+case class ConnectInitIndex(val loc: Alias, val index: Int, val exp: Arg) extends Command;
+case class EmptyCommand() extends Command;
+
+case class Component(val name: String, val ports: Array[Port], val body: Command);
+case class Circuit(val components: Array[Component], val main: String);
+
+object Commands {
+ val NoLits = Array[BigInt]()
+}
+
+import Commands._
+
+/// COMPONENTS
+
+sealed abstract class Direction(val name: String) {
+ override def toString = name
+}
+object INPUT extends Direction("input")
+object OUTPUT extends Direction("output")
+object NO_DIR extends Direction("?")
+
+object Direction {
+ def flipDirection(dir: Direction) = {
+ dir match {
+ case INPUT => OUTPUT
+ case OUTPUT => INPUT
+ case NO_DIR => NO_DIR
+ }
+ }
+}
+import Direction._
+
+/// CHISEL FRONT-END
+
+abstract class Id {
+ protected[Chisel] val _id = genSym.nextInt
+ protected[Chisel] val cid = "id_" + _id
+
+ var isDef_ = false
+ def defd: this.type = {
+ isDef_ = true
+ this
+ }
+ def isDef = isDef_
+}
+
+object debug {
+ // TODO:
+ def apply (arg: Data) = arg
+}
+
+abstract class Data(dirArg: Direction) extends Id {
+ val mod = getComponent()
+ def toType: Kind
+ var isFlipVar = dirArg == INPUT
+ def isFlip = isFlipVar
+ def dir: Direction = if (isFlip) INPUT else OUTPUT
+ def setDir(dir: Direction) {
+ isFlipVar = (dir == INPUT)
+ }
+ def init(dummy:Int = 0) = { }
+ def asInput: this.type = {
+ setDir(INPUT)
+ this
+ }
+ def asOutput: this.type = {
+ setDir(OUTPUT)
+ this
+ }
+ def flip(): this.type = {
+ isFlipVar = !isFlipVar
+ this
+ }
+ def :=(other: Data) =
+ pushCommand(Connect(this.lref, other.ref))
+ def <>(other: Data) =
+ pushCommand(BulkConnect(this.lref, other.lref))
+ final def cloneType: this.type = {
+ val res = doCloneType
+ collectElts
+ res
+ }
+ def collectElts = { }
+ def doCloneType: this.type
+ def cloneTypeWidth(width: Int): this.type
+ def lref: Alias =
+ Alias(cid)
+ def ref: Arg =
+ if (isLitValue) litArg() else Alias(cid)
+ def name = getRefForId(cid).name
+ def debugName = mod.debugName + "." + getRefForId(cid).debugName
+ def litArg(): LitArg = null
+ def litValue(): BigInt = -1
+ def isLitValue(): Boolean = false
+ def setLitValue(x: LitArg) { }
+ def floLitValue: Float = intBitsToFloat(litValue().toInt)
+ def dblLitValue: Double = longBitsToDouble(litValue().toLong)
+ def getWidth: Int = flatten.map(_.getWidth).reduce(_ + _)
+ def maxWidth(other: Data, amt: BigInt): Int = -1
+ def sumWidth(amt: BigInt): Int = -1
+ def sumWidth(other: Data, amt: BigInt): Int = -1
+ def flatten: IndexedSeq[Bits]
+ def fromBits(n: Bits): this.type = {
+ var i = 0
+ val wire = Wire(this.cloneType)
+ for (x <- wire.flatten.reverse) {
+ x := n(i + x.getWidth-1, i)
+ i += x.getWidth
+ }
+ wire.asInstanceOf[this.type]
+ }
+ def toBits: UInt = {
+ val elts = this.flatten.reverse
+ Cat(elts.head, elts.tail:_*).asUInt
+ }
+ def makeLit(value: BigInt, width: Int): this.type =
+ this.fromBits(Bits(value, width))
+
+ def toPort: Port = Port(cid, dir, toType)
+ var isReg_ = false
+ def isReg = isReg_
+ def params = if(Driver.parStack.isEmpty) Parameters.empty else Driver.parStack.top
+}
+
+object Wire {
+ def apply[T <: Data](t: T = null, init: T = null): T = {
+ val mType = if (t == null) init else t
+ if(mType == null)
+ throw new Exception("cannot infer type of Init.")
+ val x = mType.cloneType
+ // TODO: COME UP WITH MORE ROBUST WAY TO HANDLE THIS
+ pushCommand(DefWire(x.defd.cid, x.toType))
+ if (init != null)
+ pushCommand(Connect(x.lref, init.ref))
+ x
+ }
+}
+
+object Reg {
+ def apply[T <: Data](t: T = null, next: T = null, init: T = null): T = {
+ var mType = t
+ if(mType == null)
+ mType = next
+ if(mType == null)
+ mType = init
+ if(mType == null)
+ throw new Exception("cannot infer type of Reg.")
+ val x = mType.cloneType
+ x.isReg_ = true
+ pushCommand(DefRegister(x.defd.cid, x.toType))
+ if (init != null)
+ pushCommand(ConnectInit(x.lref, init.ref))
+ if (next != null)
+ x := next
+ x
+ }
+ def apply[T <: Data](outType: T): T = Reg[T](outType, null.asInstanceOf[T], null.asInstanceOf[T])
+}
+
+object Mem {
+ def apply[T <: Data](t: T, size: Int): Mem[T] = {
+ val mt = t.cloneType
+ val mem = new Mem(mt, size)
+ pushCommand(DefMemory(mt.defd.cid, mt.toType, size))
+ mem
+ }
+}
+
+class Mem[T <: Data](protected[Chisel] val t: T, n: Int) extends VecLike[T] {
+ def length: Int = n
+ def apply(idx: Int): T = apply(UInt(idx))
+ def apply(idx: UInt): T = {
+ val x = t.cloneType
+ pushCommand(DefAccessor(x.defd.cid, Alias(t.cid), NO_DIR, idx.ref))
+ x
+ }
+
+ def read(idx: UInt): T = apply(idx)
+ def write(idx: UInt, data: T): Unit = apply(idx) := data
+ def write(idx: UInt, data: T, mask: T): Unit = {
+ // This is totally fucked, but there's no true write mask support yet
+ val mask1 = mask.toBits
+ write(idx, t.fromBits((read(idx).toBits & ~mask1) | (data.toBits & mask1)))
+ }
+
+ def name = getRefForId(t.cid).name
+ def debugName = t.mod.debugName + "." + getRefForId(t.cid).debugName
+}
+
+object SeqMem {
+ def apply[T <: Data](t: T, size: Int): SeqMem[T] =
+ new SeqMem(t, size)
+}
+
+// For now, implement SeqMem in terms of Mem
+class SeqMem[T <: Data](t: T, n: Int) {
+ private val mem = Mem(t, n)
+
+ def read(addr: UInt): T = mem.read(Reg(next = addr))
+ def read(addr: UInt, enable: Bool): T = mem.read(RegEnable(addr, enable))
+
+ def write(addr: UInt, data: T): Unit = mem.write(addr, data)
+ def write(addr: UInt, data: T, mask: T): Unit = mem.write(addr, data, mask)
+}
+
+object Vec {
+ def apply[T <: Data](gen: => T, n: Int): Vec[T] =
+ new Vec((0 until n).map(i => gen.cloneType))
+ def apply[T <: Data](elts: Iterable[T]): Vec[T] = {
+ val vec = new Vec[T](elts.map(e => elts.head.cloneType))
+ val isDef = true || elts.head.isDef
+ if (vec.isReg)
+ throw new Exception("Vec of Reg Deprecated.")
+ if (isDef) {
+ pushCommand(DefWire(vec.defd.cid, vec.toType))
+ var i = 0
+ for (elt <- elts) {
+ vec(i) := elt
+ i += 1
+ }
+ }
+ vec
+ }
+ def apply[T <: Data](elt0: T, elts: T*): Vec[T] =
+ apply(elt0 +: elts.toSeq)
+ def tabulate[T <: Data](n: Int)(gen: (Int) => T): Vec[T] =
+ apply((0 until n).map(i => gen(i)))
+ def fill[T <: Data](n: Int)(gen: => T): Vec[T] =
+ Vec.tabulate(n){ i => gen }
+}
+
+abstract class Aggregate(dirArg: Direction) extends Data(dirArg) {
+ def cloneTypeWidth(width: Int): this.type = cloneType
+}
+
+class Vec[T <: Data](elts: Iterable[T], dirArg: Direction = NO_DIR) extends Aggregate(dirArg) with VecLike[T] {
+ private val self = elts.toIndexedSeq
+ private val elt0 = elts.head
+
+ // println("BEGIN VEC NAMING " + this)
+ for ((e, i) <- self zipWithIndex) {
+ // println(" NAME " + i + " -> " + cid)
+ e.collectElts
+ setIndexForId(cid, e.cid, i)
+ }
+ // println("DONE VEC NAMING " + this)
+
+ def <> (that: Iterable[T]): Unit =
+ this <> Vec(that).asInstanceOf[Data]
+
+ override def isReg = elt0.isReg
+ override def isFlip = {
+ val isSubFlip = elt0.isFlip
+ if (isFlipVar) !isSubFlip else isSubFlip
+ }
+
+ def apply(idx: UInt): T = {
+ val x = elt0.cloneType
+ pushCommand(DefAccessor(x.defd.cid, Alias(cid), NO_DIR, idx.ref))
+ x
+ }
+ def apply(idx: Int): T =
+ self(idx)
+ def toPorts: Array[Port] =
+ self.map(d => d.toPort).toArray
+ def toType: Kind =
+ VectorType(self.size, elt0.toType, isFlipVar)
+ override def doCloneType: this.type =
+ Vec(elt0.cloneType, self.size).asInstanceOf[this.type]
+ override def init(dummy:Int = 0) =
+ for (e <- self) e.init()
+ def inits (f: (Int, T, (Int, T, T) => Unit) => Unit) = {
+ var i = 0
+ def doInit (index: Int, elt: T, init: T) =
+ pushCommand(ConnectInitIndex(elt.lref, index, init.ref))
+ for (d <- self) {
+ f(i, d, doInit)
+ i += 1;
+ }
+ }
+ override def flatten: IndexedSeq[Bits] =
+ self.map(_.flatten).reduce(_ ++ _)
+
+ def length: Int = self.size
+
+ def read(idx: UInt): T = apply(idx)
+ def write(idx: UInt, data: T): Unit = apply(idx) := data
+}
+
+trait VecLike[T <: Data] extends collection.IndexedSeq[T] {
+ def read(idx: UInt): T
+ def write(idx: UInt, data: T): Unit
+ def apply(idx: UInt): T
+
+ def forall(p: T => Bool): Bool = (this map p).fold(Bool(true))(_&&_)
+ def exists(p: T => Bool): Bool = (this map p).fold(Bool(false))(_||_)
+ def contains(x: T) (implicit evidence: T <:< Bits): Bool = this.exists(_ === x)
+ def count(p: T => Bool): UInt = PopCount((this map p).toSeq)
+
+ private def indexWhereHelper(p: T => Bool) = this map p zip (0 until length).map(i => UInt(i))
+ def indexWhere(p: T => Bool): UInt = PriorityMux(indexWhereHelper(p))
+ def lastIndexWhere(p: T => Bool): UInt = PriorityMux(indexWhereHelper(p).reverse)
+ def onlyIndexWhere(p: T => Bool): UInt = Mux1H(indexWhereHelper(p))
+}
+
+// object chiselCast {
+// def apply[S <: Data, T <: Bits](i: S)(gen: Int => T): T = {
+// val b = i.toBits
+// val x = gen(b.getWidth)
+// pushCommand(DefPrim(x.defd.id, x.toType, ConvertOp, Array(b.ref), NoLits))
+// x
+// }
+// }
+
+import Literal._
+
+class BitPat(val value: String, val width: Int) extends Data(NO_DIR) {
+ def cloneTypeWidth(width: Int): this.type = cloneType
+ override def dir: Direction = NO_DIR
+ override def setDir(dir: Direction): Unit = { }
+ override def toType: Kind = UIntType(UnknownWidth(), isFlip)
+ override def getWidth: Int = width
+ override def flatten: IndexedSeq[Bits] = throw new Exception("BitPat.flatten")
+ override def doCloneType: this.type =
+ new BitPat(value, width).asInstanceOf[this.type]
+ def fromInt(x: BigInt): BitPat = BitPat(x.toString(2), -1).asInstanceOf[this.type]
+ val (bits, mask, swidth) = parseLit(value)
+ def zEquals(other: Bits): Bool =
+ (Bits(toLitVal(mask, 2)) & other) === Bits(toLitVal(bits, 2))
+ def === (other: Bits): Bool = zEquals(other)
+ def != (other: Bits): Bool = !zEquals(other)
+}
+
+object BitPat {
+ def mintLit(n: String, width: Int) = {
+ assert(n(0) == 'b', "BINARY MINTS ONLY")
+ new BitPat(n.substring(1, n.length), width)
+ }
+ def apply(value: String, width: Int): BitPat = mintLit(value, width)
+ def apply(value: String): BitPat = apply(value, -1)
+}
+
+abstract class Element(dirArg: Direction, val width: Int) extends Data(dirArg) {
+ override def getWidth: Int = width
+}
+
+abstract class Bits(dirArg: Direction, width: Int) extends Element(dirArg, width) {
+ private var litValueVar: Option[LitArg] = None
+
+ override def litArg(): LitArg = litValueVar.get
+ override def isLitValue(): Boolean = litValueVar.isDefined
+ override def litValue(): BigInt = if (isLitValue) litValueVar.get.num else -1
+ override def setLitValue(x: LitArg) { litValueVar = Some(x) }
+ override def doCloneType : this.type = cloneTypeWidth(width)
+ def fromInt(x: BigInt): this.type = makeLit(x, -1)
+
+ override def flatten: IndexedSeq[Bits] = IndexedSeq(this)
+
+ final def apply(x: BigInt): Bool = {
+ val d = new Bool(dir)
+ if (isLitValue())
+ d.setLitValue(ULit((litValue() >> x.toInt) & 1, 1))
+ else
+ pushCommand(DefPrim(d.defd.cid, d.toType, BitSelectOp, Array(this.ref), Array(x)))
+ d
+ }
+ final def apply(x: Int): Bool =
+ apply(BigInt(x))
+ final def apply(x: UInt): Bool =
+ apply(x.litValue())
+
+ final def apply(x: BigInt, y: BigInt): UInt = {
+ val w = (x - y + 1).toInt
+ val d = UInt(width = w)
+ if (isLitValue()) {
+ val mask = (BigInt(1)<<d.getWidth)-BigInt(1)
+ d.setLitValue(ULit((litValue() >> y.toInt) & mask, w))
+ } else
+ pushCommand(DefPrim(d.defd.cid, d.toType, BitsExtractOp, Array(this.ref), Array(x, y)))
+ d
+ }
+ final def apply(x: Int, y: Int): UInt =
+ apply(BigInt(x), BigInt(y))
+ final def apply(x: UInt, y: UInt): UInt =
+ apply(x.litValue(), y.litValue())
+
+ def maxWidth(other: Bits, amt: Int): Int =
+ if (getWidth >= 0 && other.getWidth >= 0) ((getWidth max other.getWidth) + amt) else -1
+ override def sumWidth(amt: BigInt): Int = if (getWidth >= 0) (getWidth + amt).toInt else -1
+ def sumWidth(other: Bits, amt: BigInt): Int =
+ if (getWidth >= 0 && other.getWidth >= 0) (getWidth + other.getWidth + amt).toInt else -1
+ def sumLog2Width(other: Bits): Int =
+ if (getWidth >= 0 && other.getWidth >= 0) (getWidth + (1<<other.getWidth)).toInt else -1
+
+ def :=(other: Bits) =
+ pushCommand(Connect(this.lref, other.ref))
+
+ protected[Chisel] def unop(op: PrimOp, width: Int): this.type = {
+ val d = cloneTypeWidth(width)
+ pushCommand(DefPrim(d.defd.cid, d.toType, op, Array(this.ref), NoLits))
+ d
+ }
+ protected[Chisel] def binop(op: PrimOp, other: BigInt, width: Int): this.type = {
+ val d = cloneTypeWidth(width)
+ pushCommand(DefPrim(d.defd.cid, d.toType, op, Array(this.ref), Array(other)))
+ d
+ }
+ protected[Chisel] def binop(op: PrimOp, other: Bits, width: Int): this.type = {
+ val d = cloneTypeWidth(width)
+ pushCommand(DefPrim(d.defd.cid, d.toType, op, Array(this.ref, other.ref), NoLits))
+ d
+ }
+ protected[Chisel] def compop(op: PrimOp, other: Bits): Bool = {
+ val d = new Bool(dir)
+ pushCommand(DefPrim(d.defd.cid, d.toType, op, Array(this.ref, other.ref), NoLits))
+ d
+ }
+
+ def unary_- : Bits = Bits(0) - this
+ def unary_-% : Bits = Bits(0) -% this
+ def +& (other: Bits): Bits = binop(AddOp, other, maxWidth(other, 1))
+ def + (other: Bits): Bits = this +% other
+ def +% (other: Bits): Bits = binop(AddModOp, other, maxWidth(other, 0))
+ def -& (other: Bits): Bits = binop(SubOp, other, maxWidth(other, 1))
+ def -% (other: Bits): Bits = binop(SubModOp, other, maxWidth(other, 0))
+ def - (other: Bits): Bits = this -% other
+ def * (other: Bits): Bits = binop(TimesOp, other, sumWidth(other, 0))
+ def / (other: Bits): Bits = binop(DivideOp, other, sumWidth(0))
+ def % (other: Bits): Bits = binop(ModOp, other, sumWidth(0))
+ def << (other: BigInt): Bits = binop(ShiftLeftOp, other, sumWidth(other))
+ def << (other: Int): Bits = this << BigInt(other)
+ def << (other: Bits): Bits = binop(DynamicShiftLeftOp, other, sumLog2Width(other))
+ def >> (other: BigInt): Bits = binop(ShiftRightOp, other, sumWidth(-other))
+ def >> (other: Int): Bits = this >> BigInt(other)
+ def >> (other: Bits): Bits = binop(DynamicShiftRightOp, other, sumWidth(0))
+ def unary_~ : Bits = unop(BitNotOp, sumWidth(0))
+ def pad (other: BigInt): Bits = binop(PadOp, other, other.toInt)
+
+ def & (other: Bits): Bits = binop(BitAndOp, other, maxWidth(other, 0))
+ def | (other: Bits): Bits = binop(BitOrOp, other, maxWidth(other, 0))
+ def ^ (other: Bits): Bits = binop(BitXorOp, other, maxWidth(other, 0))
+ def ## (other: Bits): Bits = Cat(this, other)
+
+ def < (other: Bits): Bool = compop(LessOp, other)
+ def > (other: Bits): Bool = compop(GreaterOp, other)
+ def === (other: Bits): Bool = compop(EqualOp, other)
+ def != (other: Bits): Bool = compop(NotEqualOp, other)
+ def <= (other: Bits): Bool = compop(LessEqOp, other)
+ def >= (other: Bits): Bool = compop(GreaterEqOp, other)
+ def unary_! : Bool = this === Bits(0)
+
+ private def bits_redop(op: PrimOp): Bool = {
+ val d = new Bool(dir)
+ pushCommand(DefPrim(d.defd.cid, d.toType, op, Array(this.ref), NoLits))
+ d
+ }
+
+ def orR = !(this === Bits(0))
+ def andR = (this === Bits(-1))
+ def xorR = bits_redop(XorReduceOp)
+
+ def bitSet(off: UInt, dat: Bits): Bits = {
+ val bit = UInt(1, 1) << off
+ this & ~bit | dat.toSInt & bit
+ }
+
+ def toBools: Vec[Bool] = Vec.tabulate(this.getWidth)(i => this(i))
+
+ def asSInt(): SInt
+ def asUInt(): UInt
+ def toSInt(): SInt
+ def toUInt(): UInt
+ def toBool(): Bool = this(0)
+}
+
+abstract trait Num[T <: Data] {
+ // def << (b: T): T;
+ // def >> (b: T): T;
+ //def unary_-(): T;
+ def + (b: T): T;
+ def * (b: T): T;
+ def / (b: T): T;
+ def % (b: T): T;
+ def - (b: T): T;
+ def < (b: T): Bool;
+ def <= (b: T): Bool;
+ def > (b: T): Bool;
+ def >= (b: T): Bool;
+
+ def min(b: T): T = Mux(this < b, this.asInstanceOf[T], b)
+ def max(b: T): T = Mux(this < b, b, this.asInstanceOf[T])
+}
+
+class UInt(dir: Direction, width: Int) extends Bits(dir, width) with Num[UInt] {
+ override def cloneTypeWidth(w: Int): this.type =
+ new UInt(dir, w).asInstanceOf[this.type]
+
+ def toType: Kind =
+ UIntType(if (width == -1) UnknownWidth() else IntWidth(width), isFlipVar)
+
+ override def makeLit(value: BigInt, width: Int): this.type =
+ UInt(value, width).asInstanceOf[this.type]
+
+ override def unary_- = UInt(0) - this
+ override def unary_-% = UInt(0) -% this
+ def +& (other: UInt): UInt = binop(AddOp, other, maxWidth(other, 1))
+ def + (other: UInt): UInt = this +% other
+ def +% (other: UInt): UInt = binop(AddModOp, other, maxWidth(other, 0))
+ def -& (other: UInt): UInt = binop(SubOp, other, maxWidth(other, 1))
+ def - (other: UInt): UInt = this -% other
+ def -% (other: UInt): UInt = binop(SubModOp, other, maxWidth(other, 0))
+ def * (other: UInt): UInt = binop(TimesOp, other, sumWidth(other, 0))
+ def / (other: UInt): UInt = binop(DivideOp, other, sumWidth(0))
+ def % (other: UInt): UInt = binop(ModOp, other, sumWidth(0))
+ override def << (other: BigInt): UInt = binop(ShiftLeftOp, other, sumWidth(other))
+ override def << (other: Int): UInt = this << BigInt(other)
+ def << (other: UInt): UInt = binop(DynamicShiftLeftOp, other, sumLog2Width(other))
+ override def >> (other: BigInt): UInt = binop(ShiftRightOp, other, sumWidth(-other))
+ override def >> (other: Int): UInt = this >> BigInt(other)
+ def >> (other: UInt): UInt = binop(DynamicShiftRightOp, other, sumWidth(0))
+
+ override def unary_~ : UInt = unop(BitNotOp, sumWidth(0))
+ def & (other: UInt): UInt = binop(BitAndOp, other, maxWidth(other, 0))
+ def | (other: UInt): UInt = binop(BitOrOp, other, maxWidth(other, 0))
+ def ^ (other: UInt): UInt = binop(BitXorOp, other, maxWidth(other, 0))
+ def ## (other: UInt): UInt = Cat(this, other)
+
+ def < (other: UInt): Bool = compop(LessOp, other)
+ def > (other: UInt): Bool = compop(GreaterOp, other)
+ def === (other: UInt): Bool = compop(EqualOp, other)
+ def != (other: UInt): Bool = compop(NotEqualOp, other)
+ def <= (other: UInt): Bool = compop(LessEqOp, other)
+ def >= (other: UInt): Bool = compop(GreaterEqOp, other)
+
+ override def pad (other: BigInt): UInt = binop(PadOp, other, other.toInt)
+
+ def zext(): SInt = {
+ val x = SInt(width = getWidth + 1)
+ pushCommand(DefPrim(x.defd.cid, x.toType, ConvertOp, Array(ref), NoLits))
+ x
+ }
+
+ def asSInt(): SInt = {
+ val x = SInt(width = getWidth)
+ pushCommand(DefPrim(x.defd.cid, x.toType, AsSIntOp, Array(ref), NoLits))
+ x
+ }
+
+ def toSInt(): SInt = asSInt()
+ def toUInt(): UInt = this
+ def asUInt(): UInt = this
+}
+
+trait UIntFactory {
+ def apply(dir: Direction = OUTPUT, width: Int = -1) =
+ new UInt(dir, width)
+ def uintLit(value: BigInt, width: Int) = {
+ val w = if (width == -1) (1 max bitLength(value)) else width
+ // println("UINT-LIT VALUE = " + value + "(b" + value.toString(2) + ") WIDTH " + w)
+ val b = new UInt(NO_DIR, w)
+ b.setLitValue(ULit(value, w))
+ // pushCommand(DefUInt(b.defd.id, value, w))
+ b
+ }
+ def apply(value: BigInt, width: Int): UInt = uintLit(value, width)
+ def apply(value: BigInt): UInt = apply(value, -1)
+ def apply(n: String, width: Int): UInt = {
+ val bitsPerDigit = if (n(0) == 'b') 1 else if (n(0) == 'h') 4 else -1
+ apply(stringToVal(n(0), n.substring(1, n.length)),
+ if (width == -1) (bitsPerDigit * (n.length-1)) else width)
+ }
+ def apply(n: String): UInt = apply(n, -1)
+}
+
+// Bits constructors are identical to UInt constructors.
+object Bits extends UIntFactory
+object UInt extends UIntFactory
+
+class SInt(dir: Direction, width: Int) extends Bits(dir, width) with Num[SInt] {
+ override def cloneTypeWidth(w: Int): this.type =
+ new SInt(dir, w).asInstanceOf[this.type]
+ def toType: Kind =
+ SIntType(if (width == -1) UnknownWidth() else IntWidth(width), isFlipVar)
+
+ override def makeLit(value: BigInt, width: Int): this.type =
+ SInt(value, width).asInstanceOf[this.type]
+
+ override def unary_- : SInt = SInt(0, getWidth) - this
+ override def unary_-% : SInt = SInt(0, getWidth) -% this
+ def +& (other: SInt): SInt = binop(AddOp, other, maxWidth(other, 1))
+ def +% (other: SInt): SInt = binop(AddModOp, other, maxWidth(other, 0))
+ def + (other: SInt): SInt = this +% other
+ def -& (other: SInt): SInt = binop(SubOp, other, maxWidth(other, 1))
+ def -% (other: SInt): SInt = binop(SubModOp, other, maxWidth(other, 0))
+ def - (other: SInt): SInt = this -% other
+ def * (other: SInt): SInt = binop(TimesOp, other, sumWidth(other, 0))
+ def / (other: SInt): SInt = binop(DivideOp, other, sumWidth(0))
+ def % (other: SInt): SInt = binop(ModOp, other, sumWidth(0))
+ override def << (other: BigInt): SInt = binop(ShiftLeftOp, other, sumWidth(other))
+ override def << (other: Int): SInt = this << BigInt(other)
+ def << (other: UInt): SInt = binop(DynamicShiftLeftOp, other, sumLog2Width(other))
+ override def >> (other: BigInt): SInt = binop(ShiftRightOp, other, sumWidth(-other))
+ override def >> (other: Int): SInt = this >> BigInt(other)
+ def >> (other: UInt): SInt = binop(DynamicShiftRightOp, other, sumWidth(0))
+
+ override def unary_~ : SInt = unop(BitNotOp, sumWidth(0))
+ def & (other: SInt): SInt = binop(BitAndOp, other, maxWidth(other, 0))
+ def | (other: SInt): SInt = binop(BitOrOp, other, maxWidth(other, 0))
+ def ^ (other: SInt): SInt = binop(BitXorOp, other, maxWidth(other, 0))
+
+ def < (other: SInt): Bool = compop(LessOp, other)
+ def > (other: SInt): Bool = compop(GreaterOp, other)
+ def === (other: SInt): Bool = compop(EqualOp, other)
+ def != (other: SInt): Bool = compop(NotEqualOp, other)
+ def <= (other: SInt): Bool = compop(LessEqOp, other)
+ def >= (other: SInt): Bool = compop(GreaterEqOp, other)
+ def abs: UInt = Mux(this < SInt(0), (-this).toUInt, this.toUInt)
+
+ override def pad (other: BigInt): SInt = binop(PadOp, other, other.toInt)
+
+ def asUInt(): UInt = {
+ val x = UInt(width = getWidth)
+ pushCommand(DefPrim(x.defd.cid, x.toType, AsUIntOp, Array(ref), NoLits))
+ x
+ }
+ def toUInt(): UInt = asUInt()
+ def asSInt(): SInt = this
+ def toSInt(): SInt = this
+}
+
+object SInt {
+ def apply(dir: Direction = OUTPUT, width: Int = -1) =
+ new SInt(dir, width)
+ def sintLit(value: BigInt, width: Int) = {
+ val w = if (width == -1) bitLength(value) + 1 else width
+ val b = new SInt(NO_DIR, w)
+ b.setLitValue(SLit(value, w))
+ // pushCommand(DefSInt(b.defd.id, value, w))
+ b
+ }
+ def apply(value: BigInt, width: Int): SInt = sintLit(value, width)
+ def apply(value: BigInt): SInt = apply(value, -1)
+ def apply(n: String, width: Int): SInt =
+ apply(stringToVal(n(0), n.substring(1, n.length)), width)
+ def apply(n: String): SInt = apply(n, -1)
+}
+
+class Bool(dir: Direction) extends UInt(dir, 1) {
+ override def cloneTypeWidth(w: Int): this.type = new Bool(dir).asInstanceOf[this.type]
+
+ override def makeLit(value: BigInt, width: Int): this.type =
+ Bool(value).asInstanceOf[this.type]
+
+ def & (other: Bool): Bool = super.&(other).asInstanceOf[Bool]
+ def | (other: Bool): Bool = super.|(other).asInstanceOf[Bool]
+ def ^ (other: Bool): Bool = super.^(other).asInstanceOf[Bool]
+ override def unary_~ : Bool = super.unary_~.asInstanceOf[Bool]
+
+ def || (that: Bool): Bool = this | that
+ def && (that: Bool): Bool = this & that
+}
+object Bool {
+ def apply(dir: Direction) : Bool =
+ new Bool(dir)
+ def apply() : Bool =
+ apply(NO_DIR)
+ def boolLit(value: BigInt) = {
+ val b = new Bool(NO_DIR)
+ b.setLitValue(ULit(value, 1))
+ b
+ }
+ def apply(value: BigInt) : Bool = boolLit(value)
+ def apply(value: Boolean) : Bool = apply(if (value) 1 else 0)
+}
+
+object Mux {
+ def apply[T <: Data](cond: Bool, con: T, alt: T): T = {
+ val w = Wire(alt, init = alt)
+ when (cond) {
+ w := con
+ }
+ w
+ }
+}
+
+object Cat {
+ def apply[T <: Bits](a: T, r: T*): T = apply(a :: r.toList)
+ def apply[T <: Bits](r: Seq[T]): T = doCat(r)
+ private def doCat[T <: Data](r: Seq[T]): T = {
+ if (r.tail.isEmpty)
+ r.head
+ else {
+ val l = doCat(r.slice(0, r.length/2))
+ val h = doCat(r.slice(r.length/2, r.length))
+ val isConst = (l.isLitValue() && h.isLitValue())
+ val w = if (isConst) l.getWidth + h.getWidth else if (l.getWidth >= 0 && h.getWidth >= 0) l.getWidth + h.getWidth else -1
+ val d = l.cloneTypeWidth(w)
+ if (isConst) {
+ val c = (l.litValue() << h.getWidth) | h.litValue()
+ // println("DO-CAT L = " + l.litValue() + " LW = " + l.getWidth + " H = " + h.litValue() + " -> " + c)
+
+ d.setLitValue(ULit(c, w))
+ } else
+ pushCommand(DefPrim(d.cid, d.toType, ConcatOp, Array(l.ref, h.ref), NoLits))
+ d
+ }
+ }
+}
+
+object Bundle {
+ val keywords = HashSet[String]("elements", "flip", "toString",
+ "flatten", "binding", "asInput", "asOutput", "unary_$tilde",
+ "unary_$bang", "unary_$minus", "cloneType", "doCloneType",
+ "toUInt", "toBits",
+ "toBool", "toSInt", "asDirectionless")
+ def apply[T <: Bundle](b: => T)(implicit p: Parameters): T = {
+ Driver.parStack.push(p.push)
+ val res = b
+ Driver.parStack.pop
+ res
+ }
+ def apply[T <: Bundle](b: => T, f: PartialFunction[Any,Any]): T = {
+ val q = params.alterPartial(f)
+ apply(b)(q)
+ }
+ private def params = if(Driver.parStack.isEmpty) Parameters.empty else Driver.parStack.top
+}
+
+class Bundle(dirArg: Direction = NO_DIR) extends Aggregate(dirArg) {
+ def toPorts: Array[Port] =
+ elements.map(_._2.toPort).toArray
+ def toType: BundleType =
+ BundleType(this.toPorts, isFlipVar)
+
+ override def flatten: IndexedSeq[Bits] = {
+ val sortedElts = elements.values.toIndexedSeq sortWith (_._id < _._id)
+ sortedElts.map(_.flatten).reduce(_ ++ _)
+ }
+
+ override def init(dummy:Int = 0) =
+ for ((s, e) <- elements) e.init()
+ lazy val elements: LinkedHashMap[String, Data] = {
+ val elts = LinkedHashMap[String, Data]()
+ // println("BEGIN BUNDLE NAMING " + cid)
+ for (m <- getClass.getMethods) {
+ val name = m.getName
+ // println("NAME = " + name)
+ val rtype = m.getReturnType
+ val isInterface = classOf[Data].isAssignableFrom(rtype)
+ if (m.getParameterTypes.isEmpty &&
+ !isStatic(m.getModifiers) &&
+ isInterface &&
+ !(Bundle.keywords contains name)) {
+ val obj = m.invoke(this)
+ obj match {
+ case data: Data =>
+ // println(" NAMING " + name + " -> " + cid)
+ setFieldForId(cid, data.cid, name)
+ elts(name) = data
+ case _ => ()
+ }
+ }
+ }
+ // println("DONE BUNDLE NAMING " + cid)
+ elts
+ }
+ override def collectElts = elements
+
+ override def doCloneType : this.type = {
+ try {
+ val constructor = this.getClass.getConstructors.head
+ val res = constructor.newInstance(Array.fill(constructor.getParameterTypes.size)(null):_*)
+ res.asInstanceOf[this.type]
+ } catch {
+ case npe: java.lang.reflect.InvocationTargetException if npe.getCause.isInstanceOf[java.lang.NullPointerException] =>
+ // throwException("Parameterized Bundle " + this.getClass + " needs cloneType method. You are probably using an anonymous Bundle object that captures external state and hence is un-cloneTypeable", npe)
+ val s = "CLONE INVOCATION EXCEPTION " + this.getClass
+ error(s)
+ case e: java.lang.Exception =>
+ val s = "CLONE ANY EXCEPTION " + this.getClass
+ error(s)
+ // throwException("Parameterized Bundle " + this.getClass + " needs cloneType method", e)
+ }
+ }
+}
+
+object Module {
+ def apply[T <: Module](bc: => T)(implicit p: Parameters = params): T = {
+ Driver.modStackPushed = true
+ Driver.parStack.push(p.push)
+ val m = bc
+ val cmd = popCommands
+ popScope
+ popModule
+ m.setRefs
+ val ports = m.io.toPorts
+ val component = UniqueComponent(m.name, ports, cmd)
+ components += component
+ pushCommand(DefInstance(m.defd.cid, component.name))
+ Driver.parStack.pop
+ m
+ }
+ def apply[T <: Module](m: => T, f: PartialFunction[Any,Any]): T = {
+ val q = params.alterPartial(f)
+ apply(m)(q)
+ }
+ private def params = if(Driver.parStack.isEmpty) Parameters.empty else Driver.parStack.top
+}
+
+abstract class Module(private[Chisel] _reset: Bool = null) extends Id {
+ val parent = modulez.headOption
+ pushModule(this)
+ pushScope
+ pushCommands
+ addModule(this)
+
+ lazy val params = Module.params
+ params.path = this.getClass :: params.path
+
+ def io: Bundle
+ def ref = getRefForId(cid)
+ def lref = ref
+ val reset = if (_reset == null) Bool().defd else _reset
+ setRefForId(reset.cid, "reset")
+
+ def name = {
+ // getClass.getName.replace('.', '_')
+ getClass.getName.split('.').last
+ }
+ def debugName: String = {
+ val p = parent.getOrElse(null)
+ val pname = if (p == null) "" else (p.debugName + ".")
+ pname + getRefForId(cid).debugName
+ }
+
+ def setRefs {
+ setRefForId(io.cid, "this")
+
+ for (m <- getClass.getDeclaredMethods) {
+ val name = m.getName()
+ val types = m.getParameterTypes()
+ if (types.length == 0) {
+ val obj = m.invoke(this)
+ obj match {
+ case module: Module =>
+ setRefForId(module.cid, name)
+ module.setRefs
+ case bundle: Bundle =>
+ if (name != "io") {
+ setRefForId(bundle.cid, name)
+ }
+ case mem: Mem[_] =>
+ setRefForId(mem.t.cid, name)
+ case vec: Vec[_] =>
+ setRefForId(vec.cid, name)
+ case data: Data =>
+ setRefForId(data.cid, name)
+ // ignore anything not of those types
+ case _ => null
+ }
+ }
+ }
+ }
+
+ // TODO: actually implement assert
+ def assert(cond: Bool, msg: String): Unit = {}
+}
+
+// TODO: actually implement BlackBox (this hack just allows them to compile)
+abstract class BlackBox(private[Chisel] _reset: Bool = null) extends Module(_reset) {
+ def setVerilogParameters(s: String): Unit = {}
+}
+
+object when {
+ def execBlock(block: => Unit): Command = {
+ pushScope
+ pushCommands
+ block
+ val cmd = popCommands
+ popScope
+ cmd
+ }
+ def apply(cond: => Bool)(block: => Unit): when = {
+ new when(cond)( block )
+ }
+}
+
+import when._
+
+class when(cond: => Bool)(block: => Unit) {
+ def elsewhen (cond: => Bool)(block: => Unit): when = {
+ pushCommands
+ val res = new when(cond) ( block )
+ this.cmd.alt = popCommands
+ res
+ }
+
+ def otherwise (block: => Unit) {
+ this.cmd.alt = execBlock(block)
+ }
+
+ // Capture any commands we need to set up the conditional test.
+ pushCommands
+ val pred = cond.ref
+ val prep = popCommands
+ val conseq = execBlock(block)
+ // Assume we have an empty alternate clause.
+ // elsewhen and otherwise will update it if that isn't the case.
+ val cmd = Conditionally(prep, pred, conseq, EmptyCommand())
+ pushCommand(cmd)
+}
+
+
+/// CHISEL IR EMITTER
+
+class Emitter {
+ var indenting = 0
+ def withIndent(f: => String) = {
+ indenting += 1;
+ val res = f
+ indenting -= 1;
+ res
+ }
+ def join(parts: Array[String], sep: String) =
+ parts.foldLeft("")((s, p) => if (s == "") p else s + sep + p)
+ def join0(parts: Array[String], sep: String) =
+ parts.foldLeft("")((s, p) => s + sep + p)
+ def join0(parts: List[String], sep: String) =
+ parts.foldLeft("")((s, p) => s + sep + p)
+ def newline =
+ "\n" + join((0 until indenting).map(x => " ").toArray, "")
+ def emitDir(e: Direction, isTop: Boolean): String =
+ if (isTop) (e.name + " ") else if (e == INPUT) "flip " else ""
+ def emit(e: PrimOp): String = e.name
+ def emit(e: Arg): String = e.fullname
+ def emitPort(e: Port, isTop: Boolean): String =
+ emitDir(e.dir, isTop) + getRefForId(e.id).name + " : " + emitType(e.kind)
+ def emit(e: Width): String = {
+ e match {
+ case e: UnknownWidth => ""
+ case e: IntWidth => "<" + e.value.toString + ">"
+ }
+ }
+ def emitType(e: Kind): String = {
+ e match {
+ case e: UnknownType => "?"
+ case e: UIntType => "UInt" + emit(e.width)
+ case e: SIntType => "SInt" + emit(e.width)
+ case e: BundleType => "{" + join(e.ports.map(x => emitPort(x, false)), ", ") + "}"
+ case e: VectorType => emitType(e.kind) + "[" + e.size + "]"
+ }
+ }
+ def emit(e: Command): String = {
+ def maybeWidth (w: Int) = if (w == -1) "<?>" else ("<" + w + ">")
+ e match {
+ case e: DefUInt => "node " + e.name + " = UInt" + maybeWidth(e.width) + "(" + e.value + ")"
+ case e: DefSInt => "node " + e.name + " = SInt" + maybeWidth(e.width) + "(" + e.value + ")"
+ case e: DefFlo => "node " + e.name + " = Flo(" + e.value + ")"
+ case e: DefDbl => "node " + e.name + " = Dbl(" + e.value + ")"
+ case e: DefPrim =>
+ "node " + e.name + " = " + emit(e.op) + "(" + join(e.args.map(x => emit(x)) ++ e.lits.map(x => x.toString), ", ") + ")"
+ case e: DefWire => "wire " + e.name + " : " + emitType(e.kind)
+ case e: DefRegister => "reg " + e.name + " : " + emitType(e.kind)
+ case e: DefMemory => "cmem " + e.name + " : " + emitType(e.kind) + "[" + e.size + "]";
+ case e: DefSeqMemory => "smem " + e.name + " : " + emitType(e.kind) + "[" + e.size + "]";
+ case e: DefAccessor => "accessor " + e.name + " = " + emit(e.source) + "[" + emit(e.index) + "]"
+ case e: DefInstance => {
+ val mod = modules(e.id)
+ // update all references to the modules ports
+ setRefForId(mod.io.cid, e.name, true)
+ "inst " + e.name + " of " + e.module
+ }
+ case e: Conditionally => {
+ val prefix = if (!e.prep.isInstanceOf[EmptyCommand]) {
+ newline + emit(e.prep) + newline
+ } else {
+ ""
+ }
+ val suffix = if (!e.alt.isInstanceOf[EmptyCommand]) {
+ newline + "else : " + withIndent{ newline + emit(e.alt) }
+ } else {
+ ""
+ }
+ prefix + "when " + emit(e.pred) + " : " + withIndent{ emit(e.conseq) } + suffix
+ }
+ case e: Begin => join0(e.body.map(x => emit(x)), newline)
+ case e: Connect => emit(e.loc) + " := " + emit(e.exp)
+ case e: BulkConnect => emit(e.loc1) + " <> " + emit(e.loc2)
+ case e: ConnectInit => "on-reset " + emit(e.loc) + " := " + emit(e.exp)
+ case e: ConnectInitIndex => "on-reset " + emit(e.loc) + "[" + e.index + "] := " + emit(e.exp)
+ case e: EmptyCommand => "skip"
+ }
+ }
+ def emit(e: Component): String = {
+ withIndent{ "module " + e.name + " : " +
+ join0(e.ports.map(x => emitPort(x, true)), newline) +
+ newline + emit(e.body) }
+ }
+ def emit(e: Circuit): String =
+ withIndent{ "circuit " + e.main + " : " + join0(e.components.map(x => emit(x)), newline) }
+}
diff --git a/src/main/scala/Chisel/Driver.scala b/src/main/scala/Chisel/Driver.scala
new file mode 100644
index 00000000..c4a26221
--- /dev/null
+++ b/src/main/scala/Chisel/Driver.scala
@@ -0,0 +1,420 @@
+/*
+ Copyright (c) 2011, 2012, 2013, 2014 The Regents of the University of
+ California (Regents). All Rights Reserved. Redistribution and use in
+ source and binary forms, with or without modification, are permitted
+ provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above
+ copyright notice, this list of conditions and the following
+ two paragraphs of disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ two paragraphs of disclaimer in the documentation and/or other materials
+ provided with the distribution.
+ * Neither the name of the Regents nor the names of its contributors
+ may be used to endorse or promote products derived from this
+ software without specific prior written permission.
+
+ IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
+ SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS,
+ ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
+ REGENTS HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE. THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF
+ ANY, PROVIDED HEREUNDER IS PROVIDED "AS IS". REGENTS HAS NO OBLIGATION
+ TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR
+ MODIFICATIONS.
+*/
+
+package Chisel
+import Builder._
+import Direction._
+import ChiselError._
+
+import collection.mutable.{ArrayBuffer, HashSet, HashMap, Stack, LinkedHashSet, Queue => ScalaQueue}
+import scala.math.min
+import java.io.File
+import java.io.InputStream
+import java.io.OutputStream
+import java.io.PrintStream
+
+trait FileSystemUtilities {
+ /** Ensures a directory *dir* exists on the filesystem. */
+ def ensureDir(dir: String): String = {
+ val d = dir + (if (dir == "" || dir(dir.length-1) == '/') "" else "/")
+ new File(d).mkdirs()
+ d
+ }
+
+ def createOutputFile(name: String): java.io.FileWriter = {
+ val baseDir = ensureDir(Driver.targetDir)
+ new java.io.FileWriter(baseDir + name)
+ }
+}
+
+class ChiselException(message: String, cause: Throwable) extends Exception(message, cause)
+
+object throwException {
+ def apply(s: String, t: Throwable = null) = {
+ val xcpt = new ChiselException(s, t)
+ findFirstUserLine(xcpt.getStackTrace) foreach { u => xcpt.setStackTrace(Array(u)) }
+ throw xcpt
+ }
+}
+
+object chiselMain {
+ val wrapped = true
+ val unwrapped = false
+
+ def apply[T <: Module](args: Array[String], gen: () => T): (Circuit, T) =
+ Driver(args, gen, wrapped)
+
+ def apply[T <: Module](args: Array[String], gen: () => T, ftester: T => Tester[T]): (Circuit, T) =
+ Driver(args, gen, ftester, wrapped)
+
+ // Assumes gen needs to be wrapped in Module()
+ def run[T <: Module] (args: Array[String], gen: () => T): (Circuit, T) =
+ Driver(args, gen, unwrapped)
+
+ def run[T <: Module] (args: Array[String], gen: () => T, ftester: T => Tester[T]): (Circuit, T) =
+ Driver(args, gen, ftester, unwrapped)
+}
+
+//Is this antiquated?
+object chiselMainTest {
+ def apply[T <: Module](args: Array[String], gen: () => T)(tester: T => Tester[T]): (Circuit, T) = {
+ chiselMain(args, gen, tester)
+ }
+}
+
+object Driver extends FileSystemUtilities{
+ def apply[T <: Module](args: Array[String], gen: () => T, wrapped:Boolean = true): (Circuit, T) = {
+ initChisel(args)
+ try {
+ if(wrapped) execute(gen) else executeUnwrapped(gen)
+ } finally {
+ ChiselError.report
+ if (ChiselError.hasErrors && !getLineNumbers) {
+ println("Re-running Chisel in debug mode to obtain erroneous line numbers...")
+ // apply(args :+ "--lineNumbers", gen, wrapped)
+ }
+ }
+ }
+
+ def apply[T <: Module](args: Array[String], gen: () => T,
+ ftester: T => Tester[T], wrapped:Boolean): (Circuit, T) = {
+ val (circuit, mod) = apply(args, gen, wrapped)
+ if (isTesting) test(mod, ftester)
+ (circuit, mod)
+ }
+
+ private def executeUnwrapped[T <: Module](gen: () => T): (Circuit, T) = {
+ if (!chiselConfigMode.isEmpty && !chiselConfigClassName.isEmpty) {
+ println("CHISEL PARAMS")
+ val name = appendString(chiselProjectName,chiselConfigClassName)
+ val config = try {
+ Class.forName(name).newInstance.asInstanceOf[ChiselConfig]
+ } catch {
+ case e: java.lang.ClassNotFoundException =>
+ throwException("Could not find the ChiselConfig subclass you asked for (\"" +
+ name + "\"), did you misspell it?", e)
+ }
+ val world = if(chiselConfigMode.get == "collect") {
+ new Collector(config.topDefinitions,config.knobValues)
+ } else { new Instance(config.topDefinitions,config.knobValues) }
+ val p = Parameters.root(world)
+ config.topConstraints.foreach(c => p.constrain(c))
+ val (circuit, mod) = execute(() => Module(gen())(p))
+ if(chiselConfigMode.get == "collect") {
+ val v = createOutputFile(chiselConfigClassName.get + ".knb")
+ v.write(world.getKnobs)
+ v.close
+ val w = createOutputFile(chiselConfigClassName.get + ".cst")
+ w.write(world.getConstraints)
+ w.close
+ }
+ (circuit, mod)
+ }
+ else {
+ execute(() => Module(gen()))
+ }
+ }
+
+ private def execute[T <: Module](gen: () => T): (Circuit, T) = {
+ val emitter = new Emitter
+ val (c, mod) = build{ gen() }
+ // setTopComponent(c)
+ if (!isTesting) {
+ val s = emitter.emit( c )
+ // println(c.components(0))
+ val filename = c.main + ".fir"
+ // println("FILENAME " + filename)
+ // println("S = " + s)
+ val out = createOutputFile(filename)
+ out.write(s)
+ /* Params - If dumping design, dump space to pDir*/
+ if (chiselConfigMode == None || chiselConfigMode.get == "instance") {
+ if(chiselConfigDump && !Dump.dump.isEmpty) {
+ val w = createOutputFile(appendString(Some(topComponent.name),chiselConfigClassName) + ".prm")
+ w.write(Dump.getDump); w.close
+ }
+ }
+ out.close()
+ }
+ (c, mod)
+ }
+
+ private def test[T <: Module](mod: T, ftester: T => Tester[T]): Unit = {
+ var res = false
+ var tester: Tester[T] = null
+ try {
+ tester = ftester(mod)
+ } finally {
+ if (tester != null && tester.process != null)
+ res = tester.finish()
+ }
+ println(if (res) "PASSED" else "*** FAILED ***")
+ if(!res) throwException("Module under test FAILED at least one test vector.")
+ }
+
+ def elapsedTime: Long = System.currentTimeMillis - startTime
+
+ def initChisel(args: Array[String]): Unit = {
+ ChiselError.clear()
+ warnInputs = false
+ warnOutputs = false
+ saveConnectionWarnings = false
+ saveComponentTrace = false
+ dontFindCombLoop = false
+ isGenHarness = false
+ isDebug = false
+ getLineNumbers = false
+ isCSE = false
+ isIoDebug = true
+ isVCD = false
+ isVCDMem = false
+ isReportDims = false
+ targetDir = "."
+ components.clear()
+ sortedComps.clear()
+ compStack.clear()
+ stackIndent = 0
+ printStackStruct.clear()
+ // blackboxes.clear()
+ chiselOneHotMap.clear()
+ chiselOneHotBitMap.clear()
+ isCompiling = false
+ isCheckingPorts = false
+ isTesting = false
+ isDebugMem = false
+ isSupportW0W = false
+ partitionIslands = false
+ lineLimitFunctions = 0
+ minimumLinesPerFile = 0
+ shadowRegisterInObject = false
+ allocateOnlyNeededShadowRegisters = false
+ compileInitializationUnoptimized = false
+ useSimpleQueue = false
+ parallelMakeJobs = 0
+ isVCDinline = false
+ isSupportW0W = false
+ hasMem = false
+ hasSRAM = false
+ sramMaxSize = 0
+ topComponent = null
+ // clocks.clear()
+ // implicitReset.isIo = true
+ // implicitReset.setName("reset")
+ // implicitClock = new Clock()
+ // implicitClock.setName("clk")
+ isInGetWidth = false
+ startTime = System.currentTimeMillis
+ modStackPushed = false
+
+ readArgs(args)
+ }
+
+ private def readArgs(args: Array[String]): Unit = {
+ var i = 0
+ var backendName = "c" // Default backend is Cpp.
+ while (i < args.length) {
+ val arg = args(i)
+ arg match {
+ case "--Wall" => {
+ saveConnectionWarnings = true
+ saveComponentTrace = true
+ isCheckingPorts = true
+ }
+ case "--wi" => warnInputs = true
+ case "--wo" => warnOutputs = true
+ case "--wio" => {warnInputs = true; warnOutputs = true}
+ case "--Wconnection" => saveConnectionWarnings = true
+ case "--Wcomponent" => saveComponentTrace = true
+ case "--W0W" => isSupportW0W = true
+ case "--noW0W" => isSupportW0W = false
+ case "--noCombLoop" => dontFindCombLoop = true
+ case "--genHarness" => isGenHarness = true
+ case "--debug" => isDebug = true
+ case "--lineNumbers" => getLineNumbers = true
+ case "--cse" => isCSE = true
+ case "--ioDebug" => isIoDebug = true
+ case "--noIoDebug" => isIoDebug = false
+ case "--vcd" => isVCD = true
+ case "--vcdMem" => isVCDMem = true
+ case "--v" => backendName = "v"
+ // case "--moduleNamePrefix" => Backend.moduleNamePrefix = args(i + 1); i += 1
+ case "--inlineMem" => isInlineMem = true
+ case "--noInlineMem" => isInlineMem = false
+ case "--assert" => isAssert = true
+ case "--noAssert" => isAssert = false
+ case "--debugMem" => isDebugMem = true
+ case "--partitionIslands" => partitionIslands = true
+ case "--lineLimitFunctions" => lineLimitFunctions = args(i + 1).toInt; i += 1
+ case "--minimumLinesPerFile" => minimumLinesPerFile = args(i + 1).toInt; i += 1
+ case "--shadowRegisterInObject" => shadowRegisterInObject = true
+ case "--allocateOnlyNeededShadowRegisters" => allocateOnlyNeededShadowRegisters = true
+ case "--compileInitializationUnoptimized" => compileInitializationUnoptimized = true
+ case "--useSimpleQueue" => useSimpleQueue = true
+ case "--parallelMakeJobs" => parallelMakeJobs = args(i + 1).toInt; i += 1
+ case "--isVCDinline" => isVCDinline = true
+ case "--backend" => backendName = args(i + 1); i += 1
+ case "--compile" => isCompiling = true
+ case "--test" => isTesting = true
+ case "--targetDir" => targetDir = args(i + 1); i += 1
+ case "--include" => includeArgs = args(i + 1).split(' ').toList; i += 1
+ case "--checkPorts" => isCheckingPorts = true
+ case "--reportDims" => isReportDims = true
+ //Jackhammer Flags
+ case "--configCollect" => chiselConfigMode = Some("collect"); chiselConfigClassName = Some(getArg(args(i+1),1)); chiselProjectName = Some(getArg(args(i+1),0)); i+=1; //dump constraints in dse dir
+ case "--configInstance" => chiselConfigMode = Some("instance"); chiselConfigClassName = Some(getArg(args(i+1),1)); chiselProjectName = Some(getArg(args(i+1),0)); i+=1; //use ChiselConfig to supply parameters
+ case "--configDump" => chiselConfigDump = true; //when using --configInstance, write Dump parameters to .prm file in targetDir
+ case "--dumpTestInput" => dumpTestInput = true
+ case "--testerSeed" => {
+ testerSeedValid = true
+ testerSeed = args(i+1).toLong
+ i += 1
+ }
+ case "--emitTempNodes" => {
+ isDebug = true
+ emitTempNodes = true
+ }
+ /*
+ // Dreamer configuration flags
+ case "--numRows" => {
+ if (backend.isInstanceOf[FloBackend]) {
+ backend.asInstanceOf[FloBackend].DreamerConfiguration.numRows = args(i+1).toInt
+ }
+ i += 1
+ }
+ case "--numCols" => {
+ if (backend.isInstanceOf[FloBackend]) {
+ backend.asInstanceOf[FloBackend].DreamerConfiguration.numCols = args(i+1).toInt
+ }
+ i += 1
+ }
+ */
+ case any => ChiselError.warning("'" + arg + "' is an unknown argument.")
+ }
+ i += 1
+ }
+ // Check for bogus flags
+ if (!isVCD) {
+ isVCDinline = false
+ }
+ // Set the backend after we've interpreted all the arguments.
+ // (The backend may want to configure itself based on the arguments.)
+ backend = backendName match {
+ case "v" => new VerilogBackend
+ case "c" => new CppBackend
+ case "flo" => new FloBackend
+ case "dot" => new DotBackend
+ case "fpga" => new FPGABackend
+ case "sysc" => new SysCBackend
+ case _ => Class.forName(backendName).newInstance.asInstanceOf[Backend]
+ }
+ }
+
+ var warnInputs = false
+ var warnOutputs = false
+ var saveConnectionWarnings = false
+ var saveComponentTrace = false
+ var dontFindCombLoop = false
+ var isDebug = false
+ var getLineNumbers = false
+ var isCSE = false
+ var isIoDebug = true
+ var isVCD = false
+ var isVCDMem = false
+ var isInlineMem = true
+ var isGenHarness = false
+ var isReportDims = false
+ var includeArgs: List[String] = Nil
+ var targetDir: String = null
+ var isCompiling = false
+ var isCheckingPorts = false
+ var isTesting = false
+ var isAssert = true
+ var isDebugMem = false
+ var partitionIslands = false
+ var lineLimitFunctions = 0
+ var minimumLinesPerFile = 0
+ var shadowRegisterInObject = false
+ var allocateOnlyNeededShadowRegisters = false
+ var compileInitializationUnoptimized = false
+ var useSimpleQueue = false
+ var parallelMakeJobs = 0
+ var isVCDinline = false
+ var isSupportW0W = false
+ var hasMem = false
+ var hasSRAM = false
+ var sramMaxSize = 0
+ var backend: Backend = null
+ var topComponent: Module = null
+ val components = ArrayBuffer[Module]()
+ val sortedComps = ArrayBuffer[Module]()
+ // val blackboxes = ArrayBuffer[BlackBox]()
+ val chiselOneHotMap = HashMap[(UInt, Int), UInt]()
+ val chiselOneHotBitMap = HashMap[(Bits, Int), Bool]()
+ val compStack = Stack[Module]()
+ val parStack = new Stack[Parameters]
+ var stackIndent = 0
+ val printStackStruct = ArrayBuffer[(Int, Module)]()
+ // val clocks = ArrayBuffer[Clock]()
+ // val implicitReset = Bool(INPUT)
+ // var implicitClock: Clock = null
+ var isInGetWidth: Boolean = false
+ var modStackPushed: Boolean = false
+ var modAdded: Boolean = false
+ var startTime = 0L
+ /* ChiselConfig flags */
+ var chiselConfigClassName: Option[String] = None
+ var chiselProjectName: Option[String] = None
+ var chiselConfigMode: Option[String] = None
+ var chiselConfigDump: Boolean = false
+
+ def appendString(s1:Option[String],s2:Option[String]):String = {
+ if(s1.isEmpty && s2.isEmpty) "" else {
+ if(!s1.isEmpty) {
+ s1.get + (if(!s2.isEmpty) "." + s2.get else "")
+ } else {
+ if(!s2.isEmpty) s2.get else ""
+ }
+ }
+ }
+ def getArg(s:String,i:Int):String = s.split('.')(i)
+
+ // Setting this to TRUE will case the test harness to print its
+ // standard input stream to a file.
+ var dumpTestInput = false
+
+ // Setting this to TRUE will initialize the tester's RNG with the
+ // seed below.
+ var testerSeedValid = false
+ var testerSeed = System.currentTimeMillis()
+
+ // Setting this to TRUE will result in temporary values (ie, nodes
+ // named "T*") to be emited to the VCD file.
+ var emitTempNodes = false
+}
diff --git a/src/main/scala/Chisel/Enum.scala b/src/main/scala/Chisel/Enum.scala
new file mode 100644
index 00000000..3bc24220
--- /dev/null
+++ b/src/main/scala/Chisel/Enum.scala
@@ -0,0 +1,44 @@
+/*
+ Copyright (c) 2011, 2012, 2013, 2014 The Regents of the University of
+ California (Regents). All Rights Reserved. Redistribution and use in
+ source and binary forms, with or without modification, are permitted
+ provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above
+ copyright notice, this list of conditions and the following
+ two paragraphs of disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ two paragraphs of disclaimer in the documentation and/or other materials
+ provided with the distribution.
+ * Neither the name of the Regents nor the names of its contributors
+ may be used to endorse or promote products derived from this
+ software without specific prior written permission.
+
+ IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
+ SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS,
+ ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
+ REGENTS HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE. THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF
+ ANY, PROVIDED HEREUNDER IS PROVIDED "AS IS". REGENTS HAS NO OBLIGATION
+ TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR
+ MODIFICATIONS.
+*/
+
+package Chisel
+import Literal._
+
+object Enum {
+ /** create n enum values of given type */
+ def apply[T <: Bits](nodeType: T, n: Int): List[T] = (Range(0, n, 1).map(x => (Lit(x, sizeof(n-1))(nodeType)))).toList;
+
+ /** create enum values of given type and names */
+ def apply[T <: Bits](nodeType: T, l: Symbol *): Map[Symbol, T] = (l.toList zip (Range(0, l.length, 1).map(x => Lit(x, sizeof(l.length-1))(nodeType)))).toMap;
+
+ /** create enum values of given type and names */
+ def apply[T <: Bits](nodeType: T, l: List[Symbol]): Map[Symbol, T] = (l zip (Range(0, l.length, 1).map(x => Lit(x, sizeof(l.length-1))(nodeType)))).toMap;
+
+}
diff --git a/src/main/scala/Chisel/Error.scala b/src/main/scala/Chisel/Error.scala
new file mode 100644
index 00000000..1ad5414d
--- /dev/null
+++ b/src/main/scala/Chisel/Error.scala
@@ -0,0 +1,167 @@
+/*
+ Copyright (c) 2011, 2012, 2013, 2014 The Regents of the University of
+ California (Regents). All Rights Reserved. Redistribution and use in
+ source and binary forms, with or without modification, are permitted
+ provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above
+ copyright notice, this list of conditions and the following
+ two paragraphs of disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ two paragraphs of disclaimer in the documentation and/or other materials
+ provided with the distribution.
+ * Neither the name of the Regents nor the names of its contributors
+ may be used to endorse or promote products derived from this
+ software without specific prior written permission.
+
+ IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
+ SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS,
+ ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
+ REGENTS HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE. THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF
+ ANY, PROVIDED HEREUNDER IS PROVIDED "AS IS". REGENTS HAS NO OBLIGATION
+ TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR
+ MODIFICATIONS.
+*/
+
+package Chisel
+import scala.collection.mutable.ArrayBuffer
+
+/** This Singleton implements a log4j compatible interface.
+ It is used through out the Chisel package to report errors and warnings
+ detected at runtime.
+ */
+object ChiselError {
+ var hasErrors: Boolean = false;
+ val ChiselErrors = new ArrayBuffer[ChiselError];
+
+ def clear() {
+ ChiselErrors.clear()
+ hasErrors = false
+ }
+
+ /** emit an error message */
+ def error(mf: => String, line: StackTraceElement) {
+ hasErrors = true
+ ChiselErrors += new ChiselError(() => mf, line)
+ }
+
+ def error(m: String) {
+ val stack = Thread.currentThread().getStackTrace
+ error(m, findFirstUserLine(stack) getOrElse stack(0))
+ }
+
+ /** Emit an informational message
+ (useful to track long running passes) */
+ def info(m: String): Unit =
+ println(tag("info", Console.MAGENTA) + " [%2.3f] ".format(Driver.elapsedTime/1e3) + m)
+
+ /** emit a warning message */
+ def warning(m: => String) {
+ val stack = Thread.currentThread().getStackTrace
+ ChiselErrors += new ChiselError(() => m,
+ findFirstUserLine(stack) getOrElse stack(0), 1)
+ }
+
+ def findFirstUserLine(stack: Array[StackTraceElement]): Option[StackTraceElement] = {
+ findFirstUserInd(stack) map { stack(_) }
+ }
+
+ def findFirstUserInd(stack: Array[StackTraceElement]): Option[Int] = {
+ def isUserCode(ste: StackTraceElement): Boolean = {
+ val className = ste.getClassName()
+ try {
+ val cls = Class.forName(className)
+ if( cls.getSuperclass() == classOf[Module] ) {
+ true
+ } else {
+ /* XXX Do it the old way until we figure if it is safe
+ to remove from Node.scala
+ var line: StackTraceElement = findFirstUserLine(Thread.currentThread().getStackTrace)
+ */
+ val dotPos = className.lastIndexOf('.')
+ if( dotPos > 0 ) {
+ (className.subSequence(0, dotPos) != "Chisel") && !className.contains("scala") &&
+ !className.contains("java") && !className.contains("$$")
+ } else {
+ false
+ }
+ }
+ } catch {
+ case e: java.lang.ClassNotFoundException => false
+ }
+ }
+ val idx = stack.indexWhere(isUserCode)
+ if(idx < 0) {
+ println("COULDN'T FIND LINE NUMBER (" + stack(1) + ")")
+ None
+ } else {
+ Some(idx)
+ }
+ }
+
+ // Print stack frames up to and including the "user" stack frame.
+ def printChiselStackTrace() {
+ val stack = Thread.currentThread().getStackTrace
+ val idx = ChiselError.findFirstUserInd(stack)
+ idx match {
+ case None => {}
+ case Some(x) => for (i <- 0 to x) println(stack(i))
+ }
+ }
+
+ /** Prints error messages generated by Chisel at runtime. */
+ def report() {
+ if (!ChiselErrors.isEmpty) {
+ for(err <- ChiselErrors) err.print;
+ }
+ }
+
+ /** Throws an exception if there has been any error recorded
+ before this point. */
+ def checkpoint() {
+ if(hasErrors) {
+ throw new IllegalStateException(
+ Console.UNDERLINED + "CODE HAS " +
+ Console.UNDERLINED + Console.BOLD + ChiselErrors.filter(_.isError).length + Console.RESET +
+ Console.UNDERLINED + " " +
+ Console.UNDERLINED + Console.RED + "ERRORS" + Console.RESET +
+ Console.UNDERLINED + " and " +
+ Console.UNDERLINED + Console.BOLD + ChiselErrors.filter(_.isWarning).length + Console.RESET +
+ Console.UNDERLINED + " " +
+ Console.UNDERLINED + Console.YELLOW + "WARNINGS" + Console.RESET)
+ }
+ }
+
+ def tag(name: String, color: String): String =
+ s"[${color}${name}${Console.RESET}]"
+}
+
+class ChiselError(val errmsgFun: () => String, val errline: StackTraceElement,
+val errlevel: Int = 0) {
+
+ val level = errlevel
+ val line = errline
+ val msgFun = errmsgFun
+
+ def isError = (level == 0)
+ def isWarning = (level == 1)
+
+ def print() {
+ /* Following conventions for error formatting */
+ val levelstr =
+ if (isError) ChiselError.tag("error", Console.RED)
+ else ChiselError.tag("warn", Console.YELLOW)
+ if( line != null ) {
+ println(levelstr + " " + line.getFileName + ":" +
+ line.getLineNumber + ": " + msgFun() +
+ " in class " + line.getClassName)
+ } else {
+ println(levelstr + ": " + msgFun())
+ }
+ }
+}
diff --git a/src/main/scala/Chisel/FP.scala b/src/main/scala/Chisel/FP.scala
new file mode 100644
index 00000000..c22ee475
--- /dev/null
+++ b/src/main/scala/Chisel/FP.scala
@@ -0,0 +1,321 @@
+/*
+ Copyright (c) 2011, 2012, 2013, 2014 The Regents of the University of
+ California (Regents). All Rights Reserved. Redistribution and use in
+ source and binary forms, with or without modification, are permitted
+ provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above
+ copyright notice, this list of conditions and the following
+ two paragraphs of disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ two paragraphs of disclaimer in the documentation and/or other materials
+ provided with the distribution.
+ * Neither the name of the Regents nor the names of its contributors
+ may be used to endorse or promote products derived from this
+ software without specific prior written permission.
+
+ IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
+ SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS,
+ ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
+ REGENTS HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE. THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF
+ ANY, PROVIDED HEREUNDER IS PROVIDED "AS IS". REGENTS HAS NO OBLIGATION
+ TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR
+ MODIFICATIONS.
+*/
+
+package Chisel
+import Chisel._
+import Builder._
+import ChiselError._
+import Commands.NoLits
+
+/// FLO
+
+object Flo {
+ def apply(x: Float): Flo = floLit(x)
+ def apply(x: Double): Flo = Flo(x.toFloat)
+ def floLit(value: Float): Flo = {
+ val b = new Flo(NO_DIR, Some(value))
+ pushCommand(DefFlo(b.defd.cid, value))
+ b
+ }
+ def apply(dir: Direction = null): Flo =
+ new Flo(dir)
+}
+
+object FloPrimOp {
+ val FloNeg = PrimOp("flo-neg")
+ val FloAdd = PrimOp("flo-add")
+ val FloSub = PrimOp("flo-sub")
+ val FloMul = PrimOp("flo-mul")
+ val FloDiv = PrimOp("flo-div")
+ val FloMod = PrimOp("flo-mod")
+ val FloEqual = PrimOp("flo-equal")
+ val FloNotEqual = PrimOp("flo-not-equal")
+ val FloGreater = PrimOp("flo-greater")
+ val FloLess = PrimOp("flo-less")
+ val FloLessEqual = PrimOp("flo-less-equal")
+ val FloGreaterEqual = PrimOp("flo-greater-equal")
+ val FloPow = PrimOp("flo-pow")
+ val FloSin = PrimOp("flo-sin")
+ val FloCos = PrimOp("flo-cos")
+ val FloTan = PrimOp("flo-tan")
+ val FloAsin = PrimOp("flo-asin")
+ val FloAcos = PrimOp("flo-acos")
+ val FloAtan = PrimOp("flo-atan")
+ val FloSqrt = PrimOp("flo-sqrt")
+ val FloFloor = PrimOp("flo-floor")
+ val FloCeil = PrimOp("flo-ceil")
+ val FloRound = PrimOp("flo-round")
+ val FloLog = PrimOp("flo-log")
+ val FloToBits = PrimOp("flo-to-bits")
+ val BitsToFlo = PrimOp("bits-to-flo")
+}
+import FloPrimOp._
+
+class Flo(dir: Direction = NO_DIR, val value:Option[Float] = None) extends Element(dir, 32) with Num[Flo] {
+ type T = Flo;
+ override def floLitValue: Float = value.get
+ def cloneTypeWidth(width: Int): this.type = cloneType
+ override def fromBits(n: Bits): this.type = {
+ val d = cloneType
+ pushCommand(DefPrim(d.defd.cid, d.toType, BitsToFlo, Array(this.ref), NoLits))
+ d
+ }
+ override def toBits: UInt = {
+ val d = new UInt(dir, 32)
+ pushCommand(DefPrim(d.defd.cid, d.toType, FloToBits, Array(this.ref), NoLits))
+ d
+ }
+ def toType: Kind = FloType(isFlip)
+ def doCloneType: this.type = new Flo(dir).asInstanceOf[this.type]
+ def flatten: IndexedSeq[Bits] = IndexedSeq(toBits)
+
+ def fromInt(x: Int): Flo =
+ Flo(x.toFloat).asInstanceOf[this.type]
+
+ private def flo_unop(op: PrimOp): Flo = {
+ val d = cloneType
+ pushCommand(DefPrim(d.defd.cid, d.toType, op, Array(this.ref), NoLits))
+ d
+ }
+ private def flo_binop(op: PrimOp, other: Flo): Flo = {
+ val d = cloneType
+ pushCommand(DefPrim(d.defd.cid, d.toType, op, Array(this.ref, other.ref), NoLits))
+ d
+ }
+ private def flo_compop(op: PrimOp, other: Flo): Bool = {
+ val d = new Bool(dir)
+ pushCommand(DefPrim(d.defd.cid, d.toType, op, Array(this.ref, other.ref), NoLits))
+ d
+ }
+
+ def unary_-() = flo_unop(FloNeg)
+ def + (b: Flo) = flo_binop(FloAdd, b)
+ def - (b: Flo) = flo_binop(FloSub, b)
+ def * (b: Flo) = flo_binop(FloMul, b)
+ def / (b: Flo) = flo_binop(FloDiv, b)
+ def % (b: Flo) = flo_binop(FloMod, b)
+ def ===(b: Flo) = flo_compop(FloEqual, b)
+ def != (b: Flo) = flo_compop(FloNotEqual, b)
+ def > (b: Flo) = flo_compop(FloGreater, b)
+ def < (b: Flo) = flo_compop(FloLess, b)
+ def <= (b: Flo) = flo_compop(FloLessEqual, b)
+ def >= (b: Flo) = flo_compop(FloGreaterEqual, b)
+ def pow (b: Flo) = flo_binop(FloPow, b)
+ def sin = flo_unop(FloSin)
+ def cos = flo_unop(FloCos)
+ def tan = flo_unop(FloTan)
+ def asin = flo_unop(FloAsin)
+ def acos = flo_unop(FloAcos)
+ def atan = flo_unop(FloAtan)
+ def sqrt = flo_unop(FloSqrt)
+ def floor = flo_unop(FloFloor)
+ def ceil = flo_unop(FloCeil)
+ def round = flo_unop(FloRound)
+ def log = flo_unop(FloLog)
+ def toSInt () = SInt(OUTPUT).fromBits(toBits)
+ def toUInt () = UInt(OUTPUT).fromBits(toBits)
+}
+
+/// DBL
+
+import java.lang.Double.doubleToLongBits
+
+object Dbl {
+ def apply(x: Float): Dbl = Dbl(x.toDouble);
+ def apply(x: Double): Dbl = dblLit(x)
+ def dblLit(value: Double): Dbl = {
+ val b = new Dbl(NO_DIR, Some(value))
+ pushCommand(DefDbl(b.defd.cid, value))
+ b
+ }
+ def apply(dir: Direction = NO_DIR): Dbl =
+ new Dbl(dir)
+}
+
+object DblPrimOp {
+ val DblNeg = PrimOp("dbl-neg")
+ val DblAdd = PrimOp("dbl-add")
+ val DblSub = PrimOp("dbl-sub")
+ val DblMul = PrimOp("dbl-mul")
+ val DblDiv = PrimOp("dbl-div")
+ val DblMod = PrimOp("dbl-mod")
+ val DblEqual = PrimOp("dbl-equal")
+ val DblNotEqual = PrimOp("dbl-not-equal")
+ val DblGreater = PrimOp("dbl-greater")
+ val DblLess = PrimOp("dbl-less")
+ val DblLessEqual = PrimOp("dbl-less-equal")
+ val DblGreaterEqual = PrimOp("dbl-greater-equal")
+ val DblPow = PrimOp("dbl-pow")
+ val DblSin = PrimOp("dbl-sin")
+ val DblCos = PrimOp("dbl-cos")
+ val DblTan = PrimOp("dbl-tan")
+ val DblAsin = PrimOp("dbl-asin")
+ val DblAcos = PrimOp("dbl-acos")
+ val DblAtan = PrimOp("dbl-atan")
+ val DblSqrt = PrimOp("dbl-sqrt")
+ val DblFloor = PrimOp("dbl-floor")
+ val DblCeil = PrimOp("dbl-ceil")
+ val DblRound = PrimOp("dbl-round")
+ val DblLog = PrimOp("dbl-log")
+ val DblToBits = PrimOp("dbl-to-bits")
+ val BitsToDbl = PrimOp("bits-to-dbl")
+}
+import DblPrimOp._
+
+class Dbl(dir: Direction, val value: Option[Double] = None) extends Element(dir, 64) with Num[Dbl] {
+ // setIsSigned
+
+ // override def setIsTypeNode = {inputs(0).setIsSigned; super.setIsTypeNode}
+
+ type T = Dbl;
+ override def dblLitValue: Double = value.get
+ def cloneTypeWidth(width: Int): this.type = cloneType
+ override def fromBits(n: Bits): this.type = {
+ val d = cloneType
+ pushCommand(DefPrim(d.defd.cid, d.toType, BitsToDbl, Array(this.ref), NoLits))
+ d
+ }
+ override def toBits: UInt = {
+ val d = new UInt(dir, 64)
+ pushCommand(DefPrim(d.defd.cid, d.toType, DblToBits, Array(this.ref), NoLits))
+ d
+ }
+ def toType: Kind = DblType(isFlip)
+ def doCloneType: this.type = new Dbl(dir).asInstanceOf[this.type]
+ def flatten: IndexedSeq[Bits] = IndexedSeq(toBits)
+
+ def fromInt(x: Int): this.type =
+ Dbl(x.toDouble).asInstanceOf[this.type]
+
+ private def dbl_unop(op: PrimOp): Dbl = {
+ val d = cloneType
+ pushCommand(DefPrim(d.defd.cid, d.toType, op, Array(this.ref), NoLits))
+ d
+ }
+ private def dbl_binop(op: PrimOp, other: Dbl): Dbl = {
+ val d = cloneType
+ pushCommand(DefPrim(d.defd.cid, d.toType, op, Array(this.ref, other.ref), NoLits))
+ d
+ }
+ private def dbl_compop(op: PrimOp, other: Dbl): Bool = {
+ val d = new Bool(dir)
+ pushCommand(DefPrim(d.defd.cid, d.toType, op, Array(this.ref, other.ref), NoLits))
+ d
+ }
+
+ def unary_-() = dbl_unop(DblNeg)
+ def + (b: Dbl) = dbl_binop(DblAdd, b)
+ def - (b: Dbl) = dbl_binop(DblSub, b)
+ def * (b: Dbl) = dbl_binop(DblMul, b)
+ def / (b: Dbl) = dbl_binop(DblDiv, b)
+ def % (b: Dbl) = dbl_binop(DblMod, b)
+ def ===(b: Dbl) = dbl_compop(DblEqual, b)
+ def != (b: Dbl) = dbl_compop(DblNotEqual, b)
+ def > (b: Dbl) = dbl_compop(DblGreater, b)
+ def < (b: Dbl) = dbl_compop(DblLess, b)
+ def <= (b: Dbl) = dbl_compop(DblLessEqual, b)
+ def >= (b: Dbl) = dbl_compop(DblGreaterEqual, b)
+ def pow (b: Dbl) = dbl_binop(DblPow, b)
+ def sin = dbl_unop(DblSin)
+ def cos = dbl_unop(DblCos)
+ def tan = dbl_unop(DblTan)
+ def asin = dbl_unop(DblAsin)
+ def acos = dbl_unop(DblAcos)
+ def atan = dbl_unop(DblAtan)
+ def sqrt = dbl_unop(DblSqrt)
+ def floor = dbl_unop(DblFloor)
+ def ceil = dbl_unop(DblCeil)
+ def round = dbl_unop(DblRound)
+ def log = dbl_unop(DblLog)
+ def toSInt () = SInt(OUTPUT).fromBits(toBits)
+ def toUInt () = UInt(OUTPUT).fromBits(toBits)
+}
+
+object Sin {
+ def apply (x: Flo): Flo = x.sin
+ def apply (x: Dbl): Dbl = x.sin
+}
+
+object Cos {
+ def apply (x: Flo): Flo = x.cos
+ def apply (x: Dbl): Dbl = x.cos
+}
+
+object Tan {
+ def apply (x: Flo): Flo = x.tan
+ def apply (x: Dbl): Dbl = x.tan
+}
+
+object ASin {
+ def apply (x: Flo): Flo = x.asin
+ def apply (x: Dbl): Dbl = x.asin
+}
+
+object ACos {
+ def apply (x: Flo): Flo = x.acos
+ def apply (x: Dbl): Dbl = x.acos
+}
+
+object ATan {
+ def apply (x: Flo): Flo = x.atan
+ def apply (x: Dbl): Dbl = x.atan
+}
+
+object Sqrt {
+ def apply (x: Flo): Flo = x.sqrt
+ def apply (x: Dbl): Dbl = x.sqrt
+}
+
+object Floor {
+ def apply (x: Flo): Flo = x.floor
+ def apply (x: Dbl): Dbl = x.floor
+}
+
+object Ceil {
+ def apply (x: Flo): Flo = x.ceil
+ def apply (x: Dbl): Dbl = x.ceil
+}
+
+object Round {
+ def apply (x: Flo): Flo = x.round
+ def apply (x: Dbl): Dbl = x.round
+}
+
+object Log {
+ def apply (x: Flo): Flo = x.log
+ def apply (x: Dbl): Dbl = x.log
+ def apply (x: Flo, p: Flo): Flo = Log(x)/Log(p)
+ def apply (x: Dbl, p: Dbl): Dbl = Log(x)/Log(p)
+}
+
+object Pow {
+ def apply (x: Flo, y: Flo): Flo = x.pow(y)
+ def apply (x: Dbl, y: Dbl): Dbl = x.pow(y)
+}
diff --git a/src/main/scala/Chisel/JHFormat.scala b/src/main/scala/Chisel/JHFormat.scala
new file mode 100644
index 00000000..e177835e
--- /dev/null
+++ b/src/main/scala/Chisel/JHFormat.scala
@@ -0,0 +1,105 @@
+/*
+ Copyright (c) 2011, 2012, 2013, 2014 The Regents of the University of
+ California (Regents). All Rights Reserved. Redistribution and use in
+ source and binary forms, with or without modification, are permitted
+ provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above
+ copyright notice, this list of conditions and the following
+ two paragraphs of disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ two paragraphs of disclaimer in the documentation and/or other materials
+ provided with the distribution.
+ * Neither the name of the Regents nor the names of its contributors
+ may be used to endorse or promote products derived from this
+ software without specific prior written permission.
+
+ IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
+ SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS,
+ ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
+ REGENTS HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE. THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF
+ ANY, PROVIDED HEREUNDER IS PROVIDED "AS IS". REGENTS HAS NO OBLIGATION
+ TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR
+ MODIFICATIONS.
+*/
+
+package Chisel
+import scala.collection.mutable.HashMap
+import scala.collection.mutable.ArrayBuffer
+import scala.io.Source
+import java.io._
+
+object JHFormat {
+ type Space = ArrayBuffer[(String,Param[Any],Int)]
+ def serialize[T<:Param[Any]](space: Space) : String = {
+ var string = new StringBuilder("")
+ for ((mname, p, gID) <- space) {
+ string ++= mname + "," + toStringParam(p) + "\n"
+ }
+ string.toString
+ }
+
+ def deserialize(filename: String):Space = {
+ var lines = io.Source.fromFile(filename).getLines
+ var space = new Space
+ while(lines.hasNext) {
+ val line = lines.next()
+ val args = line.split(",")
+ val mname = args(0)
+ val ptype = args(1)
+ val gID = args(2).toInt
+ val pname = args(3)
+ val param = ptype match {
+ case "value" => { val p = new ValueParam(pname,args(4).toInt)
+ p.gID = gID; p }
+ case "range" => { val p = new RangeParam(pname,args(4).toInt,args(5).toInt,args(6).toInt)
+ p.gID = gID; p }
+ case "less" => { val p = new LessParam(pname,args(4).toInt,args(5).toInt,space.find(i => i._3 == args(6).toInt).get._2)
+ p.gID = gID; p }
+ case "lesseq" => { val p = new LessEqParam(pname,args(4).toInt,args(5).toInt,space.find(i => i._3 == args(6).toInt).get._2)
+ p.gID = gID; p }
+ case "great" => { val p = new GreaterParam(pname,args(4).toInt,space.find(i => i._3 == args(5).toInt).get._2,args(6).toInt)
+ p.gID = gID; p }
+ case "greateq" => { val p = new GreaterEqParam(pname,args(4).toInt,space.find(i => i._3 == args(5).toInt).get._2,args(6).toInt)
+ p.gID = gID; p }
+ case "divisor" => { val p = new DivisorParam(pname,args(4).toInt,args(5).toInt,args(6).toInt,space.find(i => i._3 == args(7).toInt).get._2)
+ p.gID = gID; p }
+ case "enum" => { val p = new EnumParam(pname,args(4),args.slice(5,args.length).toList)
+ p.gID = gID; p }
+ case _ => { throw new ParamInvalidException("Unknown parameter"); new ValueParam("error",0) }
+ }
+ space += ((mname,param,gID.toInt))
+ }
+ space
+ }
+
+ def toStringParam(param: Param[Any]):String = {
+ param match {
+ case ValueParam(pname, init) =>
+ "value," + param.gID + "," + pname + "," + init
+ case RangeParam(pname, init, min, max) =>
+ "range," + param.gID + "," + pname + "," + init + "," + min + "," + max
+ case LessParam(pname, init, min, par) =>
+ "less," + param.gID + "," + pname + "," + init + "," + min + "," + par.gID
+ case LessEqParam(pname, init, min, par) =>
+ "lesseq," + param.gID + "," + pname + "," + init + "," + min + "," + par.gID
+ case GreaterParam(pname, init, par, max) =>
+ "great," + param.gID + "," + pname + "," + init + "," + par.gID + "," + max
+ case GreaterEqParam(pname, init, par, max) =>
+ "greateq," + param.gID + "," + pname + "," + init + "," + par.gID + "," + max
+ case DivisorParam(pname, init, min, max, par) =>
+ "divisor," + param.gID + "," + pname + "," + init + "," + min + "," + max + "," + par.gID
+ case EnumParam(pname, init, values) =>
+ "enum," + param.gID + "," + pname + "," + init + "," + values.mkString(",")
+ case _ =>
+ throw new ParamInvalidException("Unknown parameter class!"); ""
+ }
+ }
+
+ val spaceName = "space.prm"
+}
diff --git a/src/main/scala/Chisel/Literal.scala b/src/main/scala/Chisel/Literal.scala
new file mode 100644
index 00000000..fff2780b
--- /dev/null
+++ b/src/main/scala/Chisel/Literal.scala
@@ -0,0 +1,199 @@
+package Chisel
+import scala.math.log
+import scala.math.abs
+import scala.math.ceil
+import scala.math.max
+import scala.math.min
+import Literal._
+import ChiselError._
+
+/* Factory for literal values to be used by Bits and SInt factories. */
+object Lit {
+ def apply[T <: Bits](n: String)(gen: => T): T = {
+ makeLit(Literal(n, -1))(gen)
+ }
+
+ def apply[T <: Bits](n: String, width: Int)(gen: => T): T = {
+ makeLit(Literal(n, width))(gen)
+ }
+
+ def apply[T <: Bits](n: String, base: Char)(gen: => T): T = {
+ makeLit(Literal(-1, base, n))(gen)
+ }
+
+ def apply[T <: Bits](n: String, base: Char, width: Int)(gen: => T): T = {
+ makeLit(Literal(width, base, n))(gen)
+ }
+
+ def apply[T <: Bits](n: BigInt)(gen: => T): T = {
+ makeLit(Literal(n, signed = gen.isInstanceOf[SInt]))(gen)
+ }
+
+ def apply[T <: Bits](n: BigInt, width: Int)(gen: => T): T = {
+ val lit = Literal(n, width, signed = gen.isInstanceOf[SInt])
+ makeLit(lit)(gen)
+ }
+
+ def makeLit[T <: Bits](x: Literal)(gen: => T): T = {
+ gen.makeLit(x.value, x.width)
+ }
+}
+
+class Literal(val value: BigInt, val width: Int) { }
+
+object Literal {
+
+ private def bigMax(x: BigInt, y: BigInt): BigInt = if (x > y) x else y;
+ def sizeof(x: BigInt): Int = {
+ val y = bigMax(BigInt(1), x.abs).toDouble;
+ val res = max(1, (ceil(log(y + 1)/log(2.0))).toInt);
+ res
+ }
+
+ private def sizeof(base: Char, x: String): Int = {
+ var res = 0;
+ var first = true;
+ val size =
+ if(base == 'b') {
+ 1
+ } else if(base == 'h') {
+ 4
+ } else if(base == 'o') {
+ 3
+ } else {
+ -1
+ }
+ for(c <- x)
+ if (c == '_') {
+
+ } else if(first) {
+ first = false;
+ res += sizeof(c.asDigit);
+ } else if (c != '_') {
+ res += size;
+ }
+ res
+ }
+ val hexNibbles = "0123456789abcdef";
+ def toHexNibble(x: String, off: Int): Char = {
+ var res = 0;
+ for (i <- 0 until 4) {
+ val idx = off + i;
+ val c = if (idx < 0) '0' else x(idx);
+ res = 2 * res + (if (c == '1') 1 else 0);
+ }
+ hexNibbles(res)
+ }
+ val pads = Vector(0, 3, 2, 1);
+ def toHex(x: String): String = {
+ var res = "";
+ val numNibbles = (x.length-1) / 4 + 1;
+ val pad = pads(x.length % 4);
+ for (i <- 0 until numNibbles) {
+ res += toHexNibble(x, i*4 - pad);
+ }
+ res
+ }
+ def toLitVal(x: String): BigInt = {
+ BigInt(x.substring(2, x.length), 16)
+ }
+
+ def toLitVal(x: String, shamt: Int): BigInt = {
+ var res = BigInt(0);
+ for(c <- x)
+ if(c != '_'){
+ if(!(hexNibbles + "?").contains(c.toLower)) ChiselError.error({"Literal: " + x + " contains illegal character: " + c});
+ res = res * shamt + c.asDigit;
+ }
+ res
+ }
+
+ def removeUnderscore(x: String): String = {
+ var res = ""
+ for(c <- x){
+ if(c != '_'){
+ res = res + c
+ }
+ }
+ res
+ }
+
+ def parseLit(x: String): (String, String, Int) = {
+ var bits = "";
+ var mask = "";
+ var width = 0;
+ for (d <- x) {
+ if (d != '_') {
+ if(!"01?".contains(d)) ChiselError.error({"Literal: " + x + " contains illegal character: " + d});
+ width += 1;
+ mask = mask + (if (d == '?') "0" else "1");
+ bits = bits + (if (d == '?') "0" else d.toString);
+ }
+ }
+ (bits, mask, width)
+ }
+ def stringToVal(base: Char, x: String): BigInt = {
+ if(base == 'x') {
+ toLitVal(x, 16);
+ } else if(base == 'd') {
+ BigInt(x.toInt)
+ } else if(base == 'h') {
+ toLitVal(x, 16)
+ } else if(base == 'b') {
+ toLitVal(x, 2)
+ } else if(base == 'o') {
+ toLitVal(x, 8)
+ } else {
+ BigInt(-1)
+ }
+ }
+
+ /** Derive the bit length for a Literal
+ *
+ */
+ def bitLength(b: BigInt): Int = {
+ // Check for signedness
+ // We have seen unexpected values (one too small) when using .bitLength on negative BigInts,
+ // so use the positive value instead.
+ val usePositiveValueForBitLength = false
+ (if (usePositiveValueForBitLength && b < 0) {
+ -b
+ } else {
+ b
+ }).bitLength
+ }
+ /** Creates a *Literal* instance from a scala integer.
+ */
+ def apply(x: BigInt, width: Int = -1, signed: Boolean = false): Literal = {
+ // Check for signedness
+ // We get unexpected values (one too small) when using .bitLength on negative BigInts,
+ // so use the positive value instead.
+ val bl = bitLength(x)
+ val xWidth = if (signed) {
+ bl + 1
+ } else {
+ max(bl, 1)
+ }
+ val w = if(width == -1) xWidth else width
+ val xString = (if (x >= 0) x else (BigInt(1) << w) + x).toString(16)
+
+ if(xWidth > width && width != -1) {
+ // Is this a zero-width wire with value 0
+ if (!(x == 0 && width == 0 && Driver.isSupportW0W)) {
+ ChiselError.error({"width " + width + " is too small for literal " + x + ". Smallest allowed width is " + xWidth});
+ }
+ }
+ apply("h" + xString, w)
+ }
+ def apply(n: String, width: Int): Literal =
+ apply(width, n(0), n.substring(1, n.length));
+
+ def apply(width: Int, base: Char, literal: String): Literal = {
+ if (!"dhbo".contains(base)) {
+ ChiselError.error("no base specified");
+ }
+ new Literal(stringToVal(base, literal), width)
+ }
+}
+
+
diff --git a/src/main/scala/Chisel/Parameters.scala b/src/main/scala/Chisel/Parameters.scala
new file mode 100644
index 00000000..9a117ee0
--- /dev/null
+++ b/src/main/scala/Chisel/Parameters.scala
@@ -0,0 +1,644 @@
+/*
+ Constructing Hardware in a Scala Embedded Language, Copyright (c) 2014, The
+ Regents of the University of California, through Lawrence Berkeley National
+ Laboratory (subject to receipt of any required approvals from the U.S. Dept.
+ of Energy). All rights reserved.
+
+ If you have questions about your rights to use or distribute this software,
+ please contact Berkeley Lab's Technology Transfer Department at TTD@lbl.gov.
+
+ NOTICE. This software is owned by the U.S. Department of Energy. As such,
+ the U.S. Government has been granted for itself and others acting on its
+ behalf a paid-up, nonexclusive, irrevocable, worldwide license in the Software
+ to reproduce, prepare derivative works, and perform publicly and display
+ publicly. Beginning five (5) years after the date permission to assert
+ copyright is obtained from the U.S. Department of Energy, and subject to any
+ subsequent five (5) year renewals, the U.S. Government is granted for itself
+ and others acting on its behalf a paid-up, nonexclusive, irrevocable,
+ worldwide license in the Software to reproduce, prepare derivative works,
+ distribute copies to the public, perform publicly and display publicly, and to
+ permit others to do so.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ (1) Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ (2) Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+ (3) Neither the name of the University of California, Lawrence Berkeley
+ National Laboratory, U.S. Dept. of Energy nor the names of its contributors
+ may be used to endorse or promote products derived from this software without
+ specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ You are under no obligation whatsoever to provide any bug fixes, patches, or
+ upgrades to the features, functionality or performance of the source code
+ ("Enhancements") to anyone; however, if you choose to make your Enhancements
+ available either publicly, or directly to Lawrence Berkeley National
+ Laboratory, without imposing a separate written license agreement for such
+ Enhancements, then you hereby grant the following license: a non-exclusive,
+ royalty-free perpetual license to install, use, modify, prepare derivative
+ works, incorporate into other computer software, distribute, and sublicense
+ such enhancements or derivative works thereof, in binary and source code form.
+
+ Authors: J. Bachan, A. Izraelevitz, H. Cook
+*/
+
+package Chisel
+
+import scala.collection.immutable.{Seq=>Seq, Iterable=>Iterable}
+import scala.{collection=>readonly}
+import scala.collection.mutable
+
+// Convention: leading _'s on names means private to the outside world
+// but accessible to anything in this file.
+
+abstract trait UsesParameters {
+ def params: Parameters
+}
+
+class ParameterUndefinedException(field:Any, cause:Throwable=null)
+ extends RuntimeException("Parameter " + field + " undefined.", cause)
+class KnobUndefinedException(field:Any, cause:Throwable=null)
+ extends RuntimeException("Knob " + field + " undefined.", cause)
+
+// Knobs are top level free variables that go into the constraint solver.
+final case class Knob[T](name:Any)
+
+
+class ChiselConfig(
+ val topDefinitions: World.TopDefs = { (a,b,c) => {throw new scala.MatchError(a)}},
+ val topConstraints: List[ViewSym=>Ex[Boolean]] = List( ex => ExLit[Boolean](true) ),
+ val knobValues: Any=>Any = { case x => {throw new scala.MatchError(x)}}
+) {
+ import Implicits._
+ type Constraint = ViewSym=>Ex[Boolean]
+
+ def this(that: ChiselConfig) = this(that.topDefinitions,
+ that.topConstraints,
+ that.knobValues)
+
+ def ++(that: ChiselConfig) = {
+ new ChiselConfig(this.addDefinitions(that.topDefinitions),
+ this.addConstraints(that.topConstraints),
+ this.addKnobValues(that.knobValues))
+ }
+
+ def addDefinitions(that: World.TopDefs): World.TopDefs = {
+ (pname,site,here) => {
+ try this.topDefinitions(pname, site, here)
+ catch {
+ case e: scala.MatchError => that(pname, site, here)
+ }
+ }
+ }
+
+ def addConstraints(that: List[Constraint]):List[Constraint] = {
+ this.topConstraints ++ that
+ }
+
+
+ def addKnobValues(that: Any=>Any): Any=>Any = { case x =>
+ try this.knobValues(x)
+ catch {
+ case e: scala.MatchError => that(x)
+ }
+ }
+
+}
+
+object Dump {
+ val dump = mutable.Set[Tuple2[Any,Any]]()
+ val knobList = mutable.ListBuffer[Any]()
+ def apply[T](key:Any,value:T):T = {addToDump(key,value); value}
+ def apply[T](knob:Knob[T]):Knob[T] = {knobList += knob.name; knob}
+ def addToDump(key:Any,value:Any) = dump += ((key,value))
+ def getDump:String = dump.map(_.toString).reduce(_+"\n"+_) + "\n"
+}
+
+// objects given to the user in mask functions (site,here,up)
+abstract class View {
+ // the list of classes in our current path down the heirarchy
+ def path: List[Class[_]]
+
+ protected val deftSite: View // when views are queried without a specifying a site this is the default
+
+ // use `this` view's behavior to query for a parameters value as if
+ // the original site were `site`
+ def apply[T](pname:Any, site:View):T
+ def sym[T](pname:Any, site:View):Ex[T]
+
+ // query for a parameters value using the default site
+ final def apply[T](pname:Any):T = apply[T](pname, deftSite)
+ final def apply[T](field:Field[T]):T = apply[T](field.asInstanceOf[Any], deftSite)
+
+ final def sym[T](pname:Any):Ex[T] = sym[T](pname, deftSite)
+ final def sym[T](field:Field[T]):Ex[T] = sym[T](field.asInstanceOf[Any], deftSite)
+}
+
+/* Wrap a View to make the application return the symbolic expression,
+ * basically a shorthand to save typing '.sym'
+ * before:
+ * val v: View
+ * v.sym[Int]("x") // returns Ex[_]
+ * now:
+ * val vs = ViewSym(v)
+ * vs[Int]("xs") // Ex[_]
+*/
+final case class ViewSym(view:View) {
+ def apply[T](f:Any):Ex[T] = view.sym[T](f)
+ def apply[T](f:Field[T]):Ex[T] = view.sym[T](f)
+ def apply[T](f:Any, site:View):Ex[T] = view.sym[T](f, site)
+ def apply[T](f:Field[T], site:View):Ex[T] = view.sym[T](f, site)
+}
+
+
+// internal type to represent functions that evaluate parameter values
+abstract class _Lookup {
+ var path:List[Class[_]] = null
+
+ def apply[T](pname:Any, site:View):Ex[T]
+
+ // build a new Lookup that just defers to this one
+ final def push() = {
+ val me = this
+ new _Lookup {
+ this.path = me.path
+ def apply[T](pname:Any, site:View) = me.apply(pname, site)
+ }
+ }
+}
+
+// Internal type used as name in all ExVar[T]'s
+sealed abstract class _Var[T]
+
+// Variables which are 'free' parameters when seen from the top level.
+final case class _VarKnob[T](kname:Any) extends _Var[T] {
+ override def toString = kname.toString
+}
+// Variables whose values are computed by `expr`. The term 'let' comes
+// from the idea of 'let' bindings in functional languages i.e.:
+final case class _VarLet[T](pname:Any,expr:Ex[T]) extends _Var[T] {
+ override def toString = pname.toString + "{" + expr.toString + "}"
+}
+
+
+object World {
+ // An alias for the type of function provided by user to describe parameters that
+ // reach the top level. The return of this function can be either:
+ // Knob(k): this parameter maps to the constraint variable `k`
+ // Ex: this parameter is computed using the expression
+ // Any(thing else): variable takes a literal value
+ type TopDefs = (/*pname:*/Any,/*site:*/View,/*here:*/View) => Any/*Knob[_] | Ex[_] | Any*/
+}
+
+// Worlds collect the variable definitions and constraints seen when building hardware.
+abstract class World(
+ topDefs: World.TopDefs
+ ) {
+
+ val _knobs = new mutable.HashSet[Any]
+ abstract class _View extends View {
+ val look: _Lookup
+ def path = look.path
+
+ def apply[T](pname:Any, site:View):T = {
+ _eval(look(pname, site).asInstanceOf[Ex[T]])
+ }
+ def sym[T](pname:Any, site:View):Ex[T] = {
+ _bindLet[T](pname,look(pname, site).asInstanceOf[Ex[T]])
+ }
+ }
+
+ // evaluate an expression against this world
+ def _eval[T](e:Ex[T]):T = {
+ Ex.eval(e, {
+ case v:_VarKnob[_] => {
+ _knobs += v.kname
+ val e = _knobValue(v.kname)
+ if(Dump.knobList.contains(v.kname)) {Dump.addToDump(v.kname,e);e} else e
+ }
+ case v:_VarLet[_] => _eval(v.expr.asInstanceOf[Ex[T]])
+ })
+ }
+
+ // create a view whose default site is itself
+ def _siteView(look:_Lookup):View = {
+ val _look = look
+ new _View {
+ val look = _look
+ val deftSite = this
+ }
+ }
+
+ // create a View which with a supplied default site
+ def _otherView(look:_Lookup, deftSite:View):View = {
+ val _look = look
+ val _deft = deftSite
+ new _View {
+ val look = _look
+ val deftSite = _deft
+ }
+ }
+
+ // the top level lookup
+ def _topLook():_Lookup = {
+ class TopLookup extends _Lookup {
+ this.path = Nil
+
+ def apply[T](pname:Any, site:View):Ex[T] = {
+ val here = _otherView(this, site)
+ (
+ try topDefs(pname, site, here)
+ catch {
+ case e:scala.MatchError => throw new ParameterUndefinedException(pname, e)
+ }
+ ) match {
+ case k:Knob[T] => ExVar[T](_VarKnob[T](k.name))
+ case ex:Ex[T] => _bindLet[T](pname,ex)
+ case lit => ExLit(lit.asInstanceOf[T])
+ }
+ }
+ }
+ new TopLookup
+ }
+
+ def _bindLet[T](pname:Any,expr:Ex[T]):Ex[T]
+
+ def _constrain(e:Ex[Boolean]):Unit
+
+ def _knobValue(kname:Any):Any
+
+ def getConstraints:String = ""
+
+ def getKnobs:String = ""
+}
+
+// a world responsible for collecting all constraints in the first pass
+class Collector(
+ topDefs: World.TopDefs,
+ knobVal: Any=>Any // maps knob names to default-values
+ )
+ extends World(topDefs) {
+
+ val _constraints = new mutable.HashSet[Ex[Boolean]]
+
+ def knobs():List[Any] = {
+ _knobs.toList
+ }
+
+ def constraints():List[Ex[Boolean]] = {
+ _constraints.toList
+ }
+
+ def _bindLet[T](pname:Any,expr:Ex[T]):Ex[T] = {
+ expr match {
+ case e:ExVar[T] => expr
+ case e:ExLit[T] => expr
+ case _ => ExVar[T](_VarLet[T](pname,expr))
+ }
+ }
+
+ def _constrain(c:Ex[Boolean]) = {
+ _constraints += c // add the constraint
+
+ // Also add all equality constraints for all bound variables in the
+ // constraint expression and do it recursively for all expressions
+ // being bound to.
+ var q = List[Ex[_]](c)
+ while(!q.isEmpty) {
+ val e = q.head // pop an expression
+ q = q.tail
+ // walk over the variables in `e`
+ for(e <- Ex.unfurl(e)) {
+ e match {
+ case ExVar(_VarLet(p,e1)) => {
+ // form the equality constraint
+ val c1 = ExEq[Any](e.asInstanceOf[Ex[Any]], e1.asInstanceOf[Ex[Any]])
+ // recurse into the expression if its never been seen before
+ if(!_constraints.contains(c1)) {
+ _constraints += c1
+ q ::= e1 // push
+ }
+ }
+ case _ => {}
+ }
+ }
+ }
+ }
+
+ def _knobValue(kname:Any) = {
+ try knobVal(kname)
+ catch {
+ case e:scala.MatchError => throw new KnobUndefinedException(kname, e)
+ }
+ }
+
+ override def getConstraints:String = if(constraints.isEmpty) "" else constraints.map("( " + _.toString + " )").reduce(_ +"\n" + _) + "\n"
+
+ override def getKnobs:String = if(knobs.isEmpty) "" else {
+ knobs.map(_.toString).reduce(_ + "\n" + _) + "\n"
+ }
+}
+
+// a world instantianted to a specific mapping of knobs to values
+class Instance(
+ topDefs: World.TopDefs,
+ knobVal: Any=>Any
+ )
+ extends World(topDefs) {
+
+ def _bindLet[T](pname:Any,expr:Ex[T]):Ex[T] = expr
+ def _constrain(e:Ex[Boolean]) = {}
+ def _knobValue(kname:Any) = {
+ try knobVal(kname)
+ catch {
+ case e:scala.MatchError => throw new KnobUndefinedException(kname, e)
+ }
+ }
+}
+
+object Parameters {
+ def root(w:World) = {
+ new Parameters(w, w._topLook())
+ }
+ def empty = Parameters.root(new Collector((a,b,c) => {throw new ParameterUndefinedException(a); a},(a:Any) => {throw new KnobUndefinedException(a); a}))
+
+ // Mask making helpers
+
+ // Lift a regular function into a mask by looking for MatchError's and
+ // interpreting those as calls to up
+ def makeMask(mask:(Any,View,View,View)=>Any) = {
+ (f:Any, site:View, here:View, up:View) => {
+ try mask(f,site,here,up)
+ catch {case e:MatchError => up.sym[Any](f, site)}
+ }
+ }
+
+ // Lift a Map to be a mask.
+ def makeMask(mask:Map[Any,Any]) = {
+ (f:Any, site:View, here:View, up:View) => {
+ mask.get(f) match {
+ case Some(y) => y
+ case None => up.sym[Any](f, site)
+ }
+ }
+ }
+
+ // Lift a PartialFunction to be a mask.
+ def makeMask(mask:PartialFunction[Any,Any]) = {
+ (f:Any, site:View, here:View, up:View) => {
+
+ if(mask.isDefinedAt(f))
+ mask.apply(f)
+ else {
+ up.sym[Any](f, site)
+ }
+ }
+ }
+}
+
+class Field[T]
+
+final class Parameters(
+ private val _world: World,
+ private val _look: _Lookup
+ ) {
+
+ private def _site() = _world._siteView(_look)
+
+ // Create a new Parameters that just defers to this one. This is identical
+ // to doing an `alter` but not overriding any values.
+ def push():Parameters =
+ new Parameters(_world, _look.push())
+
+ // parameter's paths should be immutable but I foresee that not being sufficient
+ // when integrated into the chisel Module factory.
+ def path = _look.path
+ def path_=(x:List[Class[_]]) =
+ _look.path = x
+
+ def apply[T](field:Any):T =
+ _world._eval(_look(field, _site())).asInstanceOf[T]
+
+ def apply[T](field:Field[T]):T =
+ _world._eval(_look(field, _site())).asInstanceOf[T]
+
+ def constrain(gen:ViewSym=>Ex[Boolean]) = {
+ val g = gen(new ViewSym(_site()))
+ if(!_world._eval(g)) ChiselError.error("Constraint failed: " + g.toString)
+ _world._constrain(g)
+ }
+
+ private def _alter(mask:(/*field*/Any,/*site*/View,/*here*/View,/*up*/View)=>Any) = {
+ class KidLookup extends _Lookup {
+ this.path = _look.path
+
+ def apply[T](f:Any, site:View):Ex[T] = {
+ val here = _world._otherView(this, site)
+ val up = _world._otherView(_look, site)
+
+ mask(f, site, here, up) match {
+ case e:Ex[T] => e
+ case lit => ExLit(lit.asInstanceOf[T])
+ }
+ }
+ }
+
+ new Parameters(_world, new KidLookup)
+ }
+
+ def alter(mask:(/*field*/Any,/*site*/View,/*here*/View,/*up*/View)=>Any) =
+ _alter(Parameters.makeMask(mask))
+
+ def alter[T](mask:Map[T,Any]) =
+ _alter(Parameters.makeMask(mask.asInstanceOf[Map[Any,Any]]))
+
+ def alterPartial(mask:PartialFunction[Any,Any]) =
+ _alter(Parameters.makeMask(mask))
+}
+
+
+/*
+ Expression Library
+*/
+abstract class Ex[T] {
+ override def toString = Ex.pretty(this)
+}
+
+case class IntEx (expr:Ex[Int]) {
+ def === (x:IntEx):Ex[Boolean] = (ExEq[Int](expr,x.expr))
+ def + (x:IntEx):Ex[Int] = ExAdd(expr,x.expr)
+ def - (x:IntEx):Ex[Int] = ExSub(expr,x.expr)
+ def * (x:IntEx):Ex[Int] = ExMul(expr,x.expr)
+ def % (x:IntEx):Ex[Int] = ExMod(expr,x.expr)
+ def < (x:IntEx):Ex[Boolean] = ExLt(expr,x.expr)
+ def > (x:IntEx):Ex[Boolean] = ExGt(expr,x.expr)
+ def <= (x:IntEx):Ex[Boolean] = ExLte(expr,x.expr)
+ def >= (x:IntEx):Ex[Boolean] = ExGte(expr,x.expr)
+ def in (x:List[IntEx]):Ex[Boolean] = {
+ val canBound = x.map(_.expr match {
+ case e:ExVar[_] => false
+ case _ => true
+ }).reduce(_ && _)
+ if (canBound) {
+ val max = x.map(i => Ex.eval(i.expr,(x:Any)=>null)).max
+ val min = x.map(i => Ex.eval(i.expr,(x:Any)=>null)).min
+ ExAnd(IntEx(expr) in Range(min,max), IntEx(expr) _in x)
+ } else {
+ IntEx(expr) _in x
+ }
+ }
+ def in (x:Range):Ex[Boolean] = ExAnd(ExGte(expr,ExLit[Int](x.min)),ExLte(expr,ExLit[Int](x.max)))
+ private def _in (x:List[IntEx]):Ex[Boolean] = {
+ if (x.isEmpty) ExLit[Boolean](false) else {
+ ExOr(IntEx(expr) === x.head,IntEx(expr) _in x.tail)
+ }
+ }
+}
+
+case class BoolEx (expr:Ex[Boolean]) {
+ def && (x:BoolEx):Ex[Boolean] = ExAnd(expr,x.expr)
+ def || (x:BoolEx):Ex[Boolean] = ExOr(expr,x.expr)
+ def ^ (x:BoolEx):Ex[Boolean] = ExXor(expr,x.expr)
+ def === (x:BoolEx):Ex[Boolean] = ExEq[Boolean](expr,x.expr)
+ def !== (x:BoolEx):Ex[Boolean] = ExEq[Boolean](expr,x.expr)
+}
+
+object Implicits {
+ implicit def ExInt_IntEx(i:Ex[Int]):IntEx = IntEx(i)
+ implicit def Int_IntEx(i:Int):IntEx = IntEx(ExLit[Int](i))
+ implicit def ExBool_BoolEx(b:Ex[Boolean]):BoolEx = BoolEx(b)
+ implicit def Bool_IntEx(b:Boolean):BoolEx = BoolEx(ExLit[Boolean](b))
+
+ implicit def ListInt_ListExInt(l:List[Int]):List[IntEx] = l.map((x:Int) => IntEx(ExLit[Int](x)))
+ implicit def ListExInt_ListExInt(l:List[Ex[Int]]):List[IntEx] = l.map((x:Ex[Int]) => IntEx(x))
+}
+
+final case class ExLit[T](value:T) extends Ex[T]
+final case class ExVar[T](name:Any) extends Ex[T]
+
+final case class ExAnd(a:Ex[Boolean], b:Ex[Boolean]) extends Ex[Boolean]
+final case class ExOr(a:Ex[Boolean], b:Ex[Boolean]) extends Ex[Boolean]
+final case class ExXor(a:Ex[Boolean], b:Ex[Boolean]) extends Ex[Boolean]
+
+final case class ExEq[T](a:Ex[T], b:Ex[T]) extends Ex[Boolean]
+final case class ExNeq[T](a:Ex[T], b:Ex[T]) extends Ex[Boolean]
+
+final case class ExLt(a:Ex[Int], b:Ex[Int]) extends Ex[Boolean]
+final case class ExLte(a:Ex[Int], b:Ex[Int]) extends Ex[Boolean]
+final case class ExGt(a:Ex[Int], b:Ex[Int]) extends Ex[Boolean]
+final case class ExGte(a:Ex[Int], b:Ex[Int]) extends Ex[Boolean]
+final case class ExAdd(a:Ex[Int], b:Ex[Int]) extends Ex[Int]
+final case class ExSub(a:Ex[Int], b:Ex[Int]) extends Ex[Int]
+final case class ExMul(a:Ex[Int], b:Ex[Int]) extends Ex[Int]
+final case class ExMod(a:Ex[Int], b:Ex[Int]) extends Ex[Int]
+
+object Ex {
+ // evaluate an expression given a context that maps variable names to values
+ def eval[T](e:Ex[T], ctx:Any=>Any):T = e match {
+ case ExLit(v) => v.asInstanceOf[T]
+ case ExVar(nm) => ctx(nm).asInstanceOf[T]
+ case ExAnd(a,b) => eval(a,ctx) && eval(b,ctx)
+ case ExOr(a,b) => eval(a,ctx) || eval(b,ctx)
+ case ExXor(a,b) => eval(a,ctx) ^ eval(b,ctx)
+ case e:ExEq[u] => eval(e.a,ctx) == eval(e.b,ctx)
+ case e:ExNeq[u] => eval(e.a,ctx) != eval(e.b,ctx)
+ case ExLt(a,b) => eval(a,ctx) < eval(b,ctx)
+ case ExLte(a,b) => eval(a,ctx) <= eval(b,ctx)
+ case ExGt(a,b) => eval(a,ctx) > eval(b,ctx)
+ case ExGte(a,b) => eval(a,ctx) >= eval(b,ctx)
+ case ExAdd(a,b) => eval(a,ctx) + eval(b,ctx)
+ case ExSub(a,b) => eval(a,ctx) - eval(b,ctx)
+ case ExMul(a,b) => eval(a,ctx) * eval(b,ctx)
+ case ExMod(a,b) => eval(a,ctx) % eval(b,ctx)
+ }
+
+ // get shallow list of subexpressions
+ def subExs(e:Ex[_]):List[Ex[_]] = e match {
+ case ExLit(_) => Nil
+ case ExVar(_) => Nil
+ case ExAnd(a,b) => List(a,b)
+ case ExOr(a,b) => List(a,b)
+ case ExXor(a,b) => List(a,b)
+ case ExEq(a,b) => List(a,b)
+ case ExNeq(a,b) => List(a,b)
+ case ExLt(a,b) => List(a,b)
+ case ExLte(a,b) => List(a,b)
+ case ExGt(a,b) => List(a,b)
+ case ExGte(a,b) => List(a,b)
+ case ExAdd(a,b) => List(a,b)
+ case ExSub(a,b) => List(a,b)
+ case ExMul(a,b) => List(a,b)
+ case ExMod(a,b) => List(a,b)
+ }
+
+ // get all subexpressions including the expression given
+ def unfurl(e:Ex[_]):List[Ex[_]] =
+ e :: (subExs(e) flatMap unfurl)
+
+ // pretty-print expression
+ def pretty(e:Ex[_]):String = {
+ // precedence rank for deciding where to put parentheses
+ def rank(e:Ex[_]):Int = e match {
+ case e:ExAnd => 40
+ case e:ExOr => 50
+ case e:ExXor => 50
+ case e:ExEq[_] => 30
+ case e:ExNeq[_] => 30
+ case e:ExLt => 30
+ case e:ExLte => 30
+ case e:ExGt => 30
+ case e:ExGte => 30
+ case e:ExAdd => 20
+ case e:ExSub => 20
+ case e:ExMul => 20
+ case e:ExMod => 20
+ case e:ExLit[_] => 0
+ case e:ExVar[_] => 0
+ }
+
+ val r = rank(e)
+
+ def term(t:Ex[_]):String = {
+ val rt = rank(t)
+ //if(rt >= r)
+ "( " + t.toString + " )"
+ //else
+ //t.toString
+ }
+
+ import Implicits._
+ e match {
+ case ExLit(v) => v.toString
+ case e:ExVar[_]=> "$"+e.name
+ case ExAnd(a,b) => term(a)+" && "+term(b)
+ case ExOr(a,b) => term(a)+" || "+term(b)
+ case ExXor(a,b) => term(a)+" ^ "+term(b)
+ case ExEq(a,b) => term(a)+" = "+term(b)
+ case ExNeq(a,b) => term(a)+" != "+term(b)
+ case ExLt(a,b) => term(a)+" < "+term(b)
+ case ExLte(a,b) => term(a)+" <= "+term(b)
+ case ExGt(a,b) => term(a)+" > "+term(b)
+ case ExGte(a,b) => term(a)+" >= "+term(b)
+ case ExAdd(a,b) => term(a)+" + "+term(b)
+ case ExSub(a,b) => term(a)+" - "+term(b)
+ case ExMul(a,b) => term(a)+" * "+term(b)
+ case ExMod(a,b) => term(a)+" % "+term(b)
+ }
+ }
+}
diff --git a/src/main/scala/Chisel/Params.scala b/src/main/scala/Chisel/Params.scala
new file mode 100644
index 00000000..9f98c336
--- /dev/null
+++ b/src/main/scala/Chisel/Params.scala
@@ -0,0 +1,195 @@
+/*
+ Copyright (c) 2011, 2012, 2013, 2014 The Regents of the University of
+ California (Regents). All Rights Reserved. Redistribution and use in
+ source and binary forms, with or without modification, are permitted
+ provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above
+ copyright notice, this list of conditions and the following
+ two paragraphs of disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ two paragraphs of disclaimer in the documentation and/or other materials
+ provided with the distribution.
+ * Neither the name of the Regents nor the names of its contributors
+ may be used to endorse or promote products derived from this
+ software without specific prior written permission.
+
+ IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
+ SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS,
+ ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
+ REGENTS HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE. THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF
+ ANY, PROVIDED HEREUNDER IS PROVIDED "AS IS". REGENTS HAS NO OBLIGATION
+ TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR
+ MODIFICATIONS.
+*/
+
+/* Unfinished. Has 3 basic parameters available */
+package Chisel
+
+import Builder._
+// import Node._
+import Module._
+import JHFormat._
+
+import scala.collection.mutable.HashMap
+import scala.collection.mutable.ArrayBuffer
+
+import java.lang.reflect.{Type, ParameterizedType}
+
+import scala.io.Source
+import java.io._
+
+//>Params.scala: Implementation of parameter framework. Defines case class
+ //containers for parameter types. Params object is what actually stores
+ //the data structures of parameters, whether they are generated from a Chisel
+ //design, or read from a json file
+
+case class ParamInvalidException(msg: String) extends Exception
+
+abstract class Param[+T] {
+ def init: T
+ def max: Int
+ def min: Int
+ def pname: String
+ var index: Int = -2
+ var gID: Int = -1
+ var register = Params.register(getComponent(), pname, this)
+ //def register(pName: String) = { pname = pName; Params.register(jack.getComponent(), pname, this)}
+ def getValue: T = Params.getValue(getComponent(),this.pname,this).asInstanceOf[T]
+}
+
+case class ValueParam(pname:String, init: Any) extends Param[Any] {
+ val max = init.toString.toInt
+ val min = init.toString.toInt
+}
+
+case class RangeParam(pname:String, init: Int, min: Int, max: Int) extends Param[Int]
+
+case class LessParam(pname:String, init: Int, min: Int, par: Param[Any]) extends Param[Int] {
+ val max = par.max
+}
+
+case class LessEqParam(pname:String, init: Int, min: Int, par: Param[Any]) extends Param[Int] {
+ val max = par.max
+}
+
+case class GreaterParam(pname:String, init: Int, par: Param[Any], max: Int) extends Param[Int] {
+ val min = par.min
+}
+
+case class GreaterEqParam(pname:String, init: Int, par: Param[Any], max: Int) extends Param[Int] {
+ val min = par.min
+}
+
+case class DivisorParam(pname:String, init: Int, min: Int, max: Int, par: Param[Any]) extends Param[Int]
+
+case class EnumParam(pname:String, init: String, values: List[String]) extends Param[String] {
+ val max = init.toString.toInt
+ val min = init.toString.toInt
+}
+
+object IntParam {
+ def apply(name: String, init: Int) = RangeParam(name, init, init, init)
+}
+
+object Params {
+ type Space = JHFormat.Space
+ var space = new Space
+ var design = new Space
+ var modules = new HashMap[String, Module]
+ var gID: Int = 0
+
+ var buildingSpace = true
+
+ def getValue(module: Module, pname: String, p: Param[Any]) = {
+ val mname= if(module == null) "TOP" else {module.getClass.getName}
+ if(buildingSpace) p.init
+ else{
+ val x = design.find(t => (t._3) == (p.gID))
+ if(x.isEmpty){
+ throw new ParamInvalidException("Missing parameter " + pname + " in Module " + mname)
+ } else {
+ x.get._2.init
+ }
+ }
+ }
+
+ def register(module: Module, pname: String, p: Param[Any]) = {
+ val mname= if(module == null) "TOP" else {module.getClass.getName}
+ modules(mname) = module
+ if(buildingSpace) {
+ space += ((mname,p,gID))
+ }
+ p.gID = gID
+ gID += 1
+ p
+ }
+
+ def dump_file(filename: String, design: Space) = {
+ val string = JHFormat.serialize(design)
+ val writer = new PrintWriter(new File(filename))
+ println("Dumping to " + filename + ":\n" + string)
+ writer.write(string)
+ writer.close()
+ }
+
+ def dump(dir: String) = {
+ buildingSpace = false
+ dump_file(dir + "/" + JHFormat.spaceName, Params.space)
+ }
+ def load(designName: String) = {
+ buildingSpace = false
+ design = JHFormat.deserialize(designName)
+ gID = 0
+ }
+
+ def toCxxStringParams : String = {
+ var string = new StringBuilder("")
+ for ((mname, p, gID) <- space) {
+ val rmname = if (mname == "TOP") "" else modules(mname).name + "__";
+ string ++= "const int " + rmname + p.pname + " = " + toCxxStringParam(p) + ";\n"
+ }
+ string.toString
+ }
+
+ def toDotpStringParams : String = {
+ var string = new StringBuilder("")
+ for ((mname, p, gID) <- space) {
+ val rmname = if (mname == "TOP") "" else modules(mname).name + ":";
+ string ++= rmname + p.pname + " = " + toCxxStringParam(p) + "\n"
+ }
+ string.toString
+ }
+
+
+ def toCxxStringParam(param: Param[Any]) = {
+ param match {
+ // case EnumParam(init, list) =>
+ //"(range," + init + "," + list + ")"
+ // "const int " + name + " = " + init + ";\n"
+ case ValueParam(pname, init) =>
+ init.toString
+ case RangeParam(pname, init, min, max) =>
+ init.toString
+ case LessParam(pname, init, min, par) =>
+ init.toString
+ case LessEqParam(pname, init, min, par) =>
+ init.toString
+ case GreaterParam(pname, init, min, par) =>
+ init.toString
+ case GreaterEqParam(pname, init, min, par) =>
+ init.toString
+ case DivisorParam(pname, init, min, max, par) =>
+ init.toString
+ case EnumParam(pname, init, values) =>
+ init.toString
+ case _ =>
+ throw new ParamInvalidException("Unknown parameter class!"); ""
+ }
+ }
+}
diff --git a/src/main/scala/Chisel/Tester.scala b/src/main/scala/Chisel/Tester.scala
new file mode 100644
index 00000000..bdeb0f68
--- /dev/null
+++ b/src/main/scala/Chisel/Tester.scala
@@ -0,0 +1,417 @@
+/*
+ Copyright (c) 2011, 2012, 2013, 2014 The Regents of the University of
+ California (Regents). All Rights Reserved. Redistribution and use in
+ source and binary forms, with or without modification, are permitted
+ provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above
+ copyright notice, this list of conditions and the following
+ two paragraphs of disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ two paragraphs of disclaimer in the documentation and/or other materials
+ provided with the distribution.
+ * Neither the name of the Regents nor the names of its contributors
+ may be used to endorse or promote products derived from this
+ software without specific prior written permission.
+
+ IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
+ SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS,
+ ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
+ REGENTS HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE. THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF
+ ANY, PROVIDED HEREUNDER IS PROVIDED "AS IS". REGENTS HAS NO OBLIGATION
+ TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR
+ MODIFICATIONS.
+*/
+
+package Chisel
+import Chisel._
+import scala.math._
+import scala.collection.mutable.ArrayBuffer
+import scala.collection.mutable.HashMap
+import scala.util.Random
+import java.io.{File, IOException, InputStream, OutputStream, PrintStream}
+import java.lang.Double.longBitsToDouble
+import java.lang.Float.intBitsToFloat
+import java.lang.Double.doubleToLongBits
+import java.lang.Float.floatToIntBits
+import scala.sys.process._
+import scala.io.Source._
+import Literal._
+
+case class Poke(val node: Data, val index: Int, val value: BigInt);
+
+class Snapshot(val t: Int) {
+ val pokes = new ArrayBuffer[Poke]()
+}
+
+class ManualTester[+T <: Module]
+ (val c: T, val isT: Boolean = true) {
+ var testIn: InputStream = null
+ var testOut: OutputStream = null
+ var testErr: InputStream = null
+ val sb = new StringBuilder()
+ var delta = 0
+ var t = 0
+ var isTrace = isT
+
+ /**
+ * Waits until the emulator streams are ready. This is a dirty hack related
+ * to the way Process works. TODO: FIXME.
+ */
+ def waitForStreams() = {
+ var waited = 0
+ while (testOut == null || testIn == null || testErr == null) {
+ Thread.sleep(100)
+ if (waited % 10 == 0 && waited > 30) {
+ println("waiting for emulator process treams to be valid ...")
+ }
+ }
+ }
+
+ // TODO: MOVE TO SOMEWHERE COMMON TO BACKEND
+ def ensureDir(dir: String): String = {
+ val d = dir + (if (dir == "" || dir(dir.length-1) == '/') "" else "/")
+ new File(d).mkdirs()
+ d
+ }
+ def createOutputFile(name: String): java.io.FileWriter = {
+ val baseDir = ensureDir(Driver.targetDir)
+ new java.io.FileWriter(baseDir + name)
+ }
+
+ def puts(str: String) = {
+ while (testOut == null) { Thread.sleep(100) }
+ for (e <- str) testOut.write(e);
+ }
+
+ /**
+ * Sends a command to the emulator and returns the reply.
+ * The standard protocol treats a single line as a command, which always
+ * returns a single line of reply.
+ */
+ def emulatorCmd(str: String): String = {
+ // validate cmd
+ if (str contains "\n") {
+ System.err.print(s"emulatorCmd($str): command should not contain newline")
+ return "error"
+ }
+
+ waitForStreams()
+
+ // send command to emulator
+ for (e <- str) testOut.write(e);
+ testOut.write('\n');
+ testOut.flush()
+
+ // read output from emulator
+ var c = testIn.read
+ sb.clear()
+ while (c != '\n' && c != -1) {
+ if (c == 0) {
+ Thread.sleep(100)
+ }
+ sb += c.toChar
+ // Look for a "PRINT" command.
+ if (sb.length == 6 && sb.startsWith("PRINT ")) {
+ do {
+ c = testIn.read
+ sb += c.toChar
+ } while (c != ' ')
+ // Get the PRINT character count.
+ val printCommand = """^PRINT (\d+) """.r
+ val printCommand(nChars) = sb.toString
+ sb.clear()
+ for (i <- 0 until nChars.toInt) {
+ c = testIn.read
+ sb += c.toChar
+ }
+ System.out.print(sb.toString())
+ sb.clear()
+ }
+ c = testIn.read
+ }
+
+ // drain errors
+ try {
+ while(testErr.available() > 0) {
+ System.err.print(Character.toChars(testErr.read()))
+ }
+ } catch {
+ case e : IOException => testErr = null; println("ERR EXCEPTION")
+ }
+
+ if (sb == "error") {
+ System.err.print(s"FAILED: emulatorCmd($str): returned error")
+ ok = false
+ }
+ return sb.toString
+ }
+
+ /*
+ def setClocks(clocks: HashMap[Clock, Int]) {
+ var cmd = "set_clocks"
+ for (clock <- Driver.clocks) {
+ if (clock.srcClock == null) {
+ val s = BigInt(clocks(clock)).toString(16)
+ cmd = cmd + " " + s
+ }
+ }
+ emulatorCmd(cmd)
+ // TODO: check for errors in return
+ }
+ */
+
+ def doPeekBits(name: String, off: Int = -1): BigInt = {
+ if (name == "") {
+ println("Unable to peek data " + name) // TODO: USE DATA
+ -1
+ } else {
+ var cmd = ""
+ if (off != -1) {
+ cmd = "mem_peek " + name + " " + off;
+ } else {
+ cmd = "wire_peek " + name;
+ }
+ val s = emulatorCmd(cmd)
+ val rv = toLitVal(s)
+ if (isTrace) println(" PEEK " + name + " " + (if (off >= 0) (off + " ") else "") + "-> " + s)
+ rv
+ }
+ }
+
+ def peekBits(data: Data, off: Int = -1): BigInt = {
+ doPeekBits(data.debugName, off)
+ }
+
+ def signed_fix(dtype: Element, rv: BigInt): BigInt = {
+ val w = dtype.width
+ dtype match {
+ /* Any "signed" node */
+ case _: SInt | _ : Flo | _: Dbl => (if(rv >= (BigInt(1) << w - 1)) (rv - (BigInt(1) << w)) else rv)
+ /* anything else (i.e., UInt) */
+ case _ => (rv)
+ }
+ }
+
+ def peekAt[T <: Bits](data: Mem[T], off: Int): BigInt = {
+ // signed_fix(data(1), peekBits(data, off))
+ doPeekBits(data.debugName, off)
+ }
+
+ def peek(data: Bits): BigInt = {
+ signed_fix(data, peekBits(data))
+ }
+
+ def peek(data: Flo): Float = {
+ intBitsToFloat(peekBits(data).toInt)
+ }
+
+ def peek(data: Dbl): Double = {
+ longBitsToDouble(peekBits(data).toLong)
+ }
+
+ def peek(data: Aggregate /*, off: Int = -1 */): IndexedSeq[BigInt] = {
+ data.flatten.map(peek(_))
+ }
+
+ def reset(n: Int = 1) = {
+ emulatorCmd("reset " + n)
+ // TODO: check for errors in return
+ if (isTrace) println("RESET " + n)
+ }
+
+ def doPokeBits(name: String, x: BigInt, off: Int): Unit = {
+ if (name == "") {
+ println("Unable to poke data " + name) // TODO: data.toString
+ } else {
+
+ var cmd = ""
+ if (off != -1) {
+ cmd = "mem_poke " + name + " " + off;
+ } else {
+ cmd = "wire_poke " + name;
+ }
+ // Don't prefix negative numbers with "0x"
+ val radixPrefix = if (x < 0) " -0x" else " 0x"
+ val xval = radixPrefix + x.abs.toString(16)
+ cmd = cmd + xval
+ if (isTrace) {
+ println(" POKE " + name + " " + (if (off >= 0) (off + " ") else "") + "<- " + xval)
+ }
+ val rtn = emulatorCmd(cmd)
+ if (rtn != "ok") {
+ System.err.print(s"FAILED: poke(${name}) returned false")
+ ok = false
+ }
+ }
+ }
+
+ def pokeAt[T <: Bits](data: Mem[T], x: BigInt, off: Int): Unit = {
+ doPokeBits(data.debugName, x, off)
+ }
+
+ def pokeBits(data: Data, x: BigInt, off: Int = -1): Unit = {
+ doPokeBits(data.debugName, x, off)
+ }
+
+ def poke(data: Bits, x: BigInt): Unit = {
+ pokeBits(data, x)
+ }
+
+ def poke(data: Flo, x: Float): Unit = {
+ pokeBits(data, BigInt(floatToIntBits(x)))
+ }
+
+ def poke(data: Dbl, x: Double): Unit = {
+ pokeBits(data, BigInt(doubleToLongBits(x)))
+ }
+
+ def poke(data: Aggregate, x: Array[BigInt]): Unit = {
+ val kv = (data.flatten, x.reverse).zipped;
+ for ((x, y) <- kv)
+ poke(x, y)
+ }
+
+ def step(n: Int) = {
+ val target = t + n
+ val s = emulatorCmd("step " + n)
+ delta += s.toInt
+ if (isTrace) println("STEP " + n + " -> " + target)
+ t += n
+ }
+
+ def int(x: Boolean): BigInt = if (x) 1 else 0
+ def int(x: Int): BigInt = x
+ def int(x: Bits): BigInt = x.litValue()
+
+ var ok = true;
+ var failureTime = -1
+
+ def expect (good: Boolean, msg: String): Boolean = {
+ if (isTrace)
+ println(msg + " " + (if (good) "PASS" else "FAIL"))
+ if (!good) { ok = false; if (failureTime == -1) failureTime = t; }
+ good
+ }
+
+ def expect (data: Bits, expected: BigInt): Boolean = {
+ // val mask = (BigInt(1) << data) - 1
+ val got = peek(data)
+
+ // expect((got & mask) == (expected & mask),
+ expect(got == expected,
+ "EXPECT " + data.debugName + " <- 0x" + got.toString(16) + " == 0x" + expected.toString(16))
+ }
+
+ def expect (data: Aggregate, expected: Array[BigInt]): Boolean = {
+ val kv = (data.flatten, expected.reverse).zipped;
+ var allGood = true
+ for ((d, e) <- kv)
+ allGood = expect(d, e) && allGood
+ allGood
+ }
+
+ /* We need the following so scala doesn't use our "tolerant" Float version of expect.
+ */
+ def expect (data: Bits, expected: Int): Boolean = {
+ expect(data, BigInt(expected))
+ }
+ def expect (data: Bits, expected: Long): Boolean = {
+ expect(data, BigInt(expected))
+ }
+ def expect (data: Flo, expected: Double): Boolean = {
+ val got = peek(data)
+ expect(got == expected, "EXPECT " + data.debugName + " <- " + got + " == " + expected)
+ }
+ def expect (data: Dbl, expected: Double): Boolean = {
+ val got = peek(data)
+ expect(got == expected, "EXPECT " + data.debugName + " <- " + got + " == " + expected)
+ }
+
+ /* Compare the floating point value of a node with an expected floating point value.
+ * We will tolerate differences in the bottom bit.
+ */
+ def expect (data: Bits, expected: Float): Boolean = {
+ val gotBits = peek(data).toInt
+ val expectedBits = java.lang.Float.floatToIntBits(expected)
+ var gotFLoat = java.lang.Float.intBitsToFloat(gotBits)
+ var expectedFloat = expected
+ if (gotFLoat != expectedFloat) {
+ val gotDiff = gotBits - expectedBits
+ // Do we have a single bit difference?
+ if (abs(gotDiff) <= 1) {
+ expectedFloat = gotFLoat
+ }
+ }
+ expect(gotFLoat == expectedFloat,
+ "EXPECT " + data.debugName + " <- " + gotFLoat + " == " + expectedFloat)
+ }
+
+ val rnd = if (Driver.testerSeedValid) new Random(Driver.testerSeed) else new Random()
+ var process: Process = null
+
+ def start(): Process = {
+ val n = Driver.appendString(Some(c.name),Driver.chiselConfigClassName)
+ val target = Driver.targetDir + "/" + n
+ val cmd = target
+ println("OPENING " + cmd)
+ /*
+ (if (Driver.backend.isInstanceOf[FloBackend]) {
+ val dir = Driver.backend.asInstanceOf[FloBackend].floDir
+ val command = ArrayBuffer(dir + "fix-console", ":is-debug", "true", ":filename", target + ".hex", ":flo-filename", target + ".mwe.flo")
+ if (Driver.isVCD) { command ++= ArrayBuffer(":is-vcd-dump", "true") }
+ if (Driver.emitTempNodes) { command ++= ArrayBuffer(":emit-temp-nodes", "true") }
+ command ++= ArrayBuffer(":target-dir", Driver.targetDir)
+ command.mkString(" ")
+ } else {
+ target + (if (Driver.backend.isInstanceOf[VerilogBackend]) " -q +vcs+initreg+0 " else "")
+ })
+ */
+ println("SEED " + Driver.testerSeed)
+ println("STARTING " + cmd)
+ val processBuilder = Process(cmd)
+ val pio = new ProcessIO(in => testOut = in, out => testIn = out, err => testErr = err)
+ process = processBuilder.run(pio)
+ waitForStreams()
+ t = 0
+ reset(5)
+ // Skip vpd message
+ if (Driver.backend.isInstanceOf[VerilogBackend] && Driver.isDebug) {
+ var vpdmsg = testIn.read
+ while (vpdmsg != '\n' && vpdmsg != -1)
+ vpdmsg = testIn.read
+ }
+ process
+ }
+
+ def finish(): Boolean = {
+ if (process != null) {
+ emulatorCmd("quit")
+
+ if (testOut != null) {
+ testOut.flush()
+ testOut.close()
+ }
+ if (testIn != null) {
+ testIn.close()
+ }
+ if (testErr != null) {
+ testErr.close()
+ }
+
+ process.destroy()
+ }
+ println("RAN " + t + " CYCLES " + (if (ok) "PASSED" else { "FAILED FIRST AT CYCLE " + failureTime }))
+ ok
+ }
+}
+
+class Tester[+T <: Module](c: T, isTrace: Boolean = true) extends ManualTester(c, isTrace) {
+ start()
+}
+
diff --git a/src/main/scala/Chisel/utils.scala b/src/main/scala/Chisel/utils.scala
new file mode 100644
index 00000000..3bbea34a
--- /dev/null
+++ b/src/main/scala/Chisel/utils.scala
@@ -0,0 +1,561 @@
+package Chisel
+import Builder._
+import scala.math._
+
+object log2Up
+{
+ def apply(in: Int): Int = if(in == 1) 1 else ceil(log(in)/log(2)).toInt
+}
+
+object log2Ceil
+{
+ def apply(in: Int): Int = ceil(log(in)/log(2)).toInt
+}
+
+
+object log2Down
+{
+ def apply(x : Int): Int = if (x == 1) 1 else floor(log(x)/log(2.0)).toInt
+}
+
+object log2Floor
+{
+ def apply(x : Int): Int = floor(log(x)/log(2.0)).toInt
+}
+
+
+object isPow2
+{
+ def apply(in: Int): Boolean = in > 0 && ((in & (in-1)) == 0)
+}
+
+object FillInterleaved
+{
+ def apply(n: Int, in: UInt): UInt = apply(n, in.toBools)
+ def apply(n: Int, in: Seq[Bool]): UInt = Vec(in.map(Fill(n, _))).toBits
+}
+
+/** Returns the number of bits set (i.e value is 1) in the input signal.
+ */
+object PopCount
+{
+ def apply(in: Iterable[Bool]): UInt = {
+ if (in.size == 0) {
+ UInt(0)
+ } else if (in.size == 1) {
+ in.head
+ } else {
+ apply(in.slice(0, in.size/2)) + Cat(UInt(0), apply(in.slice(in.size/2, in.size)))
+ }
+ }
+ def apply(in: Bits): UInt = apply((0 until in.getWidth).map(in(_)))
+}
+
+object RegNext {
+
+ def apply[T <: Data](next: T): T = Reg[T](next, next, null.asInstanceOf[T])
+
+ def apply[T <: Data](next: T, init: T): T = Reg[T](next, next, init)
+
+}
+
+object RegInit {
+
+ def apply[T <: Data](init: T): T = Reg[T](init, null.asInstanceOf[T], init)
+
+}
+
+object RegEnable
+{
+ def apply[T <: Data](updateData: T, enable: Bool) = {
+ val r = Reg(updateData)
+ when (enable) { r := updateData }
+ r
+ }
+ def apply[T <: Data](updateData: T, resetData: T, enable: Bool) = {
+ val r = RegInit(resetData)
+ when (enable) { r := updateData }
+ r
+ }
+}
+
+/** Builds a Mux tree out of the input signal vector using a one hot encoded
+ select signal. Returns the output of the Mux tree.
+ */
+object Mux1H
+{
+ def apply[T <: Data](sel: Iterable[Bool], in: Iterable[T]): T = {
+ if (in.tail.isEmpty) in.head
+ else {
+ val masked = (sel, in).zipped map ((s, i) => Mux(s, i.toBits, Bits(0)))
+ in.head.fromBits(masked.reduceLeft(_|_))
+ }
+ }
+ def apply[T <: Data](in: Iterable[(Bool, T)]): T = {
+ val (sel, data) = in.unzip
+ apply(sel, data)
+ }
+ def apply[T <: Data](sel: Bits, in: Iterable[T]): T =
+ apply((0 until in.size).map(sel(_)), in)
+ def apply(sel: Bits, in: Bits): Bool = (sel & in).orR
+}
+
+/** Builds a Mux tree under the assumption that multiple select signals
+ can be enabled. Priority is given to the first select signal.
+
+ Returns the output of the Mux tree.
+ */
+object PriorityMux
+{
+ def apply[T <: Bits](in: Iterable[(Bool, T)]): T = {
+ if (in.size == 1) {
+ in.head._2
+ } else {
+ Mux(in.head._1, in.head._2, apply(in.tail))
+ }
+ }
+ def apply[T <: Bits](sel: Iterable[Bool], in: Iterable[T]): T = apply(sel zip in)
+ def apply[T <: Bits](sel: Bits, in: Iterable[T]): T = apply((0 until in.size).map(sel(_)), in)
+}
+
+object unless {
+ def apply(c: Bool)(block: => Unit) {
+ when (!c) { block }
+ }
+}
+
+object switch {
+ def apply(c: Bits)(block: => Unit) {
+ switchKeys.push(c)
+ block
+ switchKeys.pop()
+ }
+}
+
+object is {
+ def apply(v: Bits)(block: => Unit): Unit =
+ apply(Seq(v))(block)
+ def apply(v: Bits, vr: Bits*)(block: => Unit): Unit =
+ apply(v :: vr.toList)(block)
+ def apply(v: Iterable[Bits])(block: => Unit): Unit = {
+ val keys = switchKeys
+ if (keys.isEmpty) ChiselError.error("The 'is' keyword may not be used outside of a switch.")
+ else if (!v.isEmpty) when (v.map(_ === keys.top).reduce(_||_)) { block }
+ }
+}
+
+object MuxLookup {
+ def apply[S <: UInt, T <: Bits] (key: S, default: T, mapping: Seq[(S, T)]): T = {
+ var res = default;
+ for ((k, v) <- mapping.reverse)
+ res = Mux(k === key, v, res);
+ res
+ }
+
+}
+
+object Fill {
+ def apply(n: Int, x: Bool): UInt = n match {
+ case 0 => UInt(width=0)
+ case 1 => x
+ case x if n > 1 => UInt(0,n) - UInt(x)
+ case _ => throw new IllegalArgumentException(s"n (=$n) must be nonnegative integer.")
+ }
+ def apply(n: Int, y: UInt): UInt = {
+ n match {
+ case 0 => UInt(width=0)
+ case 1 => y
+ case x if n > 1 =>
+ val p2 = Array.ofDim[UInt](log2Up(n+1))
+ p2(0) = y
+ for (i <- 1 until p2.length)
+ p2(i) = Cat(p2(i-1), p2(i-1))
+ Cat((0 until log2Up(x+1)).filter(i => (x & (1 << i)) != 0).map(p2(_)))
+ case _ => throw new IllegalArgumentException(s"n (=$n) must be nonnegative integer.")
+ }
+ }
+}
+
+object MuxCase {
+ def apply[T <: Bits] (default: T, mapping: Seq[(Bool, T)]): T = {
+ var res = default;
+ for ((t, v) <- mapping.reverse){
+ res = Mux(t, v, res);
+ }
+ res
+ }
+}
+
+object ListLookup {
+ def apply[T <: Data](addr: UInt, default: List[T], mapping: Array[(BitPat, List[T])]): List[T] = {
+ val map = mapping.map(m => (m._1 === addr, m._2))
+ default.zipWithIndex map { case (d, i) =>
+ map.foldRight(d)((m, n) => Mux(m._1, m._2(i), n))
+ }
+ }
+}
+
+object Lookup {
+ def apply[T <: Bits](addr: UInt, default: T, mapping: Seq[(BitPat, T)]): T =
+ ListLookup(addr, List(default), mapping.map(m => (m._1, List(m._2))).toArray).head
+}
+
+/** Litte/big bit endian convertion: reverse the order of the bits in a UInt.
+*/
+object Reverse
+{
+ private def doit(in: UInt, length: Int): UInt = {
+ if (length == 1) {
+ in
+ } else if (isPow2(length) && length >= 8 && length <= 64) {
+ // Do it in logarithmic time to speed up C++. Neutral for real HW.
+ var res = in
+ var shift = length >> 1
+ var mask = UInt((BigInt(1) << length) - 1, length)
+ do {
+ mask = mask ^ (mask(length-shift-1,0) << UInt(shift))
+ res = ((res >> UInt(shift)) & mask) | (res(length-shift-1,0) << UInt(shift) & ~mask)
+ shift = shift >> 1
+ } while (shift > 0)
+ res
+ } else {
+ val half = (1 << log2Up(length))/2
+ Cat(doit(in(half-1,0), half), doit(in(length-1,half), length-half))
+ }
+ }
+ def apply(in: UInt): UInt = doit(in, in.getWidth)
+}
+
+/** Returns the n-cycle delayed version of the input signal.
+ */
+object ShiftRegister
+{
+ def apply[T <: Data](in: T, n: Int, en: Bool = Bool(true)): T =
+ {
+ // The order of tests reflects the expected use cases.
+ if (n == 1) {
+ RegEnable(in, en)
+ } else if (n != 0) {
+ RegNext(apply(in, n-1, en))
+ } else {
+ in
+ }
+ }
+}
+
+/** Returns the one hot encoding of the input UInt.
+ */
+object UIntToOH
+{
+ def apply(in: UInt, width: Int = -1): UInt =
+ if (width == -1) UInt(1) << in
+ else (UInt(1) << in(log2Up(width)-1,0))(width-1,0)
+}
+
+class Counter(val n: Int) {
+ val value = if (n == 1) UInt(0) else Reg(init=UInt(0, log2Up(n)))
+ def inc(): Bool = {
+ if (n == 1) Bool(true)
+ else {
+ val wrap = value === UInt(n-1)
+ value := Mux(Bool(!isPow2(n)) && wrap, UInt(0), value + UInt(1))
+ wrap
+ }
+ }
+}
+
+object Counter
+{
+ def apply(n: Int): Counter = new Counter(n)
+ def apply(cond: Bool, n: Int): (UInt, Bool) = {
+ val c = new Counter(n)
+ var wrap: Bool = null
+ when (cond) { wrap = c.inc() }
+ (c.value, cond && wrap)
+ }
+}
+
+class ValidIO[+T <: Data](gen2: T) extends Bundle
+{
+ val valid = Bool(OUTPUT)
+ val bits = gen2.cloneType.asOutput
+ def fire(dummy: Int = 0): Bool = valid
+ override def doCloneType: this.type = new ValidIO(gen2).asInstanceOf[this.type]
+}
+
+/** Adds a valid protocol to any interface. The standard used is
+ that the consumer uses the flipped interface.
+*/
+object Valid {
+ def apply[T <: Data](gen: T): ValidIO[T] = new ValidIO(gen)
+}
+
+class DecoupledIO[+T <: Data](gen: T) extends Bundle
+{
+ val ready = Bool(INPUT)
+ val valid = Bool(OUTPUT)
+ val bits = gen.cloneType.asOutput
+ def fire(dummy: Int = 0): Bool = ready && valid
+ override def doCloneType: this.type = new DecoupledIO(gen).asInstanceOf[this.type]
+}
+
+/** Adds a ready-valid handshaking protocol to any interface.
+ The standard used is that the consumer uses the flipped
+ interface.
+ */
+object Decoupled {
+ def apply[T <: Data](gen: T): DecoupledIO[T] = new DecoupledIO(gen)
+}
+
+class EnqIO[T <: Data](gen: T) extends DecoupledIO(gen)
+{
+ def enq(dat: T): T = { valid := Bool(true); bits := dat; dat }
+ override def init(dummy: Int = 0) = {
+ valid := Bool(false);
+ for (io <- bits.flatten)
+ io := UInt(0)
+ }
+ override def doCloneType: this.type = { new EnqIO(gen).asInstanceOf[this.type]; }
+}
+
+class DeqIO[T <: Data](gen: T) extends DecoupledIO(gen)
+{
+ flip()
+ override def init(dummy: Int = 0) = {
+ ready := Bool(false)
+ }
+ def deq(b: Boolean = false): T = { ready := Bool(true); bits }
+ override def doCloneType: this.type = { new DeqIO(gen).asInstanceOf[this.type]; }
+}
+
+
+class DecoupledIOC[+T <: Data](gen: T) extends Bundle
+{
+ val ready = Bool(INPUT)
+ val valid = Bool(OUTPUT)
+ val bits = gen.cloneType.asOutput
+}
+
+class QueueIO[T <: Data](gen: T, entries: Int) extends Bundle
+{
+ val enq = Decoupled(gen.cloneType).flip
+ val deq = Decoupled(gen.cloneType)
+ val count = UInt(OUTPUT, log2Up(entries + 1))
+}
+
+class Queue[T <: Data](gen: T, val entries: Int, pipe: Boolean = false, flow: Boolean = false, _reset: Bool = null) extends Module(_reset=_reset)
+{
+ val io = new QueueIO(gen, entries)
+
+ val ram = Mem(gen, entries)
+ val enq_ptr = Counter(entries)
+ val deq_ptr = Counter(entries)
+ val maybe_full = Reg(init=Bool(false))
+
+ val ptr_match = enq_ptr.value === deq_ptr.value
+ val empty = ptr_match && !maybe_full
+ val full = ptr_match && maybe_full
+ val maybe_flow = Bool(flow) && empty
+ val do_flow = maybe_flow && io.deq.ready
+
+ val do_enq = io.enq.ready && io.enq.valid && !do_flow
+ val do_deq = io.deq.ready && io.deq.valid && !do_flow
+ when (do_enq) {
+ ram(enq_ptr.value) := io.enq.bits
+ enq_ptr.inc()
+ }
+ when (do_deq) {
+ deq_ptr.inc()
+ }
+ when (do_enq != do_deq) {
+ maybe_full := do_enq
+ }
+
+ io.deq.valid := !empty || Bool(flow) && io.enq.valid
+ io.enq.ready := !full || Bool(pipe) && io.deq.ready
+ io.deq.bits := Mux(maybe_flow, io.enq.bits, ram(deq_ptr.value))
+
+ val ptr_diff = enq_ptr.value - deq_ptr.value
+ if (isPow2(entries)) {
+ io.count := Cat(maybe_full && ptr_match, ptr_diff)
+ } else {
+ io.count := Mux(ptr_match, Mux(maybe_full, UInt(entries), UInt(0)), Mux(deq_ptr.value > enq_ptr.value, UInt(entries) + ptr_diff, ptr_diff))
+ }
+}
+
+/** Generic hardware queue. Required parameter entries controls
+ the depth of the queues. The width of the queue is determined
+ from the inputs.
+
+ Example usage:
+ val q = new Queue(UInt(), 16)
+ q.io.enq <> producer.io.out
+ consumer.io.in <> q.io.deq
+ */
+object Queue
+{
+ def apply[T <: Data](enq: DecoupledIO[T], entries: Int = 2, pipe: Boolean = false): DecoupledIO[T] = {
+ val q = Module(new Queue(enq.bits.cloneType, entries, pipe))
+ q.io.enq.valid := enq.valid // not using <> so that override is allowed
+ q.io.enq.bits := enq.bits
+ enq.ready := q.io.enq.ready
+ q.io.deq
+ }
+}
+
+object PriorityEncoderOH
+{
+ private def encode(in: Seq[Bool]): UInt = {
+ val outs = Vec.tabulate(in.size)(i => UInt(BigInt(1) << i, in.size))
+ PriorityMux(in :+ Bool(true), outs :+ UInt(0, in.size))
+ }
+ def apply(in: Seq[Bool]): Vec[Bool] = {
+ val enc = encode(in)
+ Vec.tabulate(in.size)(enc(_))
+ }
+ def apply(in: Bits): UInt = encode((0 until in.getWidth).map(i => in(i)))
+}
+
+class ArbiterIO[T <: Data](gen: T, n: Int) extends Bundle {
+ val in = Vec(Decoupled(gen), n).flip
+ val out = Decoupled(gen)
+ val chosen = UInt(OUTPUT, log2Up(n))
+}
+
+object ArbiterCtrl
+{
+ def apply(request: Seq[Bool]): Seq[Bool] = {
+ Bool(true) +: (1 until request.length).map(i => !request.slice(0, i).foldLeft(Bool(false))(_ || _))
+ }
+}
+
+abstract class LockingArbiterLike[T <: Data](gen: T, n: Int, count: Int, needsLock: Option[T => Bool] = None) extends Module {
+ require(isPow2(count))
+ def grant: Seq[Bool]
+ val io = new ArbiterIO(gen, n)
+ val locked = if(count > 1) Reg(init=Bool(false)) else Bool(false)
+ val lockIdx = if(count > 1) Reg(init=UInt(n-1)) else UInt(n-1)
+ val chosen = Wire(UInt(width = log2Up(n)))
+
+ for ((g, i) <- grant.zipWithIndex)
+ io.in(i).ready := Mux(locked, lockIdx === UInt(i), g) && io.out.ready
+ io.out.valid := io.in(chosen).valid
+ io.out.bits := io.in(chosen).bits
+ io.chosen := chosen
+
+ if(count > 1){
+ val cnt = Reg(init=UInt(0, width = log2Up(count)))
+ val cnt_next = cnt + UInt(1)
+ when(io.out.fire()) {
+ when(needsLock.map(_(io.out.bits)).getOrElse(Bool(true))) {
+ cnt := cnt_next
+ when(!locked) {
+ locked := Bool(true)
+ lockIdx := Vec(io.in.map{ in => in.fire()}).indexWhere{i: Bool => i}
+ }
+ }
+ when(cnt_next === UInt(0)) {
+ locked := Bool(false)
+ }
+ }
+ }
+}
+
+class LockingRRArbiter[T <: Data](gen: T, n: Int, count: Int, needsLock: Option[T => Bool] = None) extends LockingArbiterLike[T](gen, n, count, needsLock) {
+ lazy val last_grant = Reg(init=UInt(0, log2Up(n)))
+ override def grant: Seq[Bool] = {
+ val ctrl = ArbiterCtrl((0 until n).map(i => io.in(i).valid && UInt(i) > last_grant) ++ io.in.map(_.valid))
+ (0 until n).map(i => ctrl(i) && UInt(i) > last_grant || ctrl(i + n))
+ }
+
+ var choose = UInt(n-1)
+ for (i <- n-2 to 0 by -1)
+ choose = Mux(io.in(i).valid, UInt(i), choose)
+ for (i <- n-1 to 1 by -1)
+ choose = Mux(io.in(i).valid && UInt(i) > last_grant, UInt(i), choose)
+ chosen := Mux(locked, lockIdx, choose)
+
+ when (io.out.fire()) { last_grant := chosen }
+}
+
+class LockingArbiter[T <: Data](gen: T, n: Int, count: Int, needsLock: Option[T => Bool] = None) extends LockingArbiterLike[T](gen, n, count, needsLock) {
+ def grant: Seq[Bool] = ArbiterCtrl(io.in.map(_.valid))
+
+ var choose = UInt(n-1)
+ for (i <- n-2 to 0 by -1) {
+ choose = Mux(io.in(i).valid, UInt(i), choose)
+ }
+ chosen := Mux(locked, lockIdx, choose)
+}
+
+/** Hardware module that is used to sequence n producers into 1 consumer.
+ Producers are chosen in round robin order.
+
+ Example usage:
+ val arb = new RRArbiter(2, UInt())
+ arb.io.in(0) <> producer0.io.out
+ arb.io.in(1) <> producer1.io.out
+ consumer.io.in <> arb.io.out
+ */
+class RRArbiter[T <: Data](gen:T, n: Int) extends LockingRRArbiter[T](gen, n, 1)
+
+/** Hardware module that is used to sequence n producers into 1 consumer.
+ Priority is given to lower producer
+
+ Example usage:
+ val arb = Module(new Arbiter(2, UInt()))
+ arb.io.in(0) <> producer0.io.out
+ arb.io.in(1) <> producer1.io.out
+ consumer.io.in <> arb.io.out
+ */
+class Arbiter[T <: Data](gen: T, n: Int) extends LockingArbiter[T](gen, n, 1)
+
+/** linear feedback shift register
+ */
+object LFSR16
+{
+ def apply(increment: Bool = Bool(true)): UInt =
+ {
+ val width = 16
+ val lfsr = Reg(init=UInt(1, width))
+ when (increment) { lfsr := Cat(lfsr(0)^lfsr(2)^lfsr(3)^lfsr(5), lfsr(width-1,1)) }
+ lfsr
+ }
+}
+
+/** A hardware module that delays data coming down the pipeline
+ by the number of cycles set by the latency parameter. Functionality
+ is similar to ShiftRegister but this exposes a Pipe interface.
+
+ Example usage:
+ val pipe = new Pipe(UInt())
+ pipe.io.enq <> produce.io.out
+ consumer.io.in <> pipe.io.deq
+ */
+object Pipe
+{
+ def apply[T <: Data](enqValid: Bool, enqBits: T, latency: Int): ValidIO[T] = {
+ if (latency == 0) {
+ val out = Valid(enqBits)
+ out.valid <> enqValid
+ out.bits <> enqBits
+ out
+ } else {
+ val v = Reg(Bool(), next=enqValid, init=Bool(false))
+ val b = RegEnable(enqBits, enqValid)
+ apply(v, b, latency-1)
+ }
+ }
+ def apply[T <: Data](enqValid: Bool, enqBits: T): ValidIO[T] = apply(enqValid, enqBits, 1)
+ def apply[T <: Data](enq: ValidIO[T], latency: Int = 1): ValidIO[T] = apply(enq.valid, enq.bits, latency)
+}
+
+class Pipe[T <: Data](gen: T, latency: Int = 1) extends Module
+{
+ val io = new Bundle {
+ val enq = Valid(gen).flip
+ val deq = Valid(gen)
+ }
+
+ io.deq <> Pipe(io.enq, latency)
+}