summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.md9
-rw-r--r--build.sbt7
-rw-r--r--src/main/scala/Backend.scala10
-rw-r--r--src/main/scala/Core.scala1154
-rw-r--r--src/main/scala/Driver.scala421
-rw-r--r--src/main/scala/Enum.scala44
-rw-r--r--src/main/scala/Error.scala167
-rw-r--r--src/main/scala/FP.scala319
-rw-r--r--src/main/scala/Literal.scala199
-rw-r--r--src/main/scala/Tester.scala389
-rw-r--r--src/main/scala/utils.scala253
11 files changed, 2972 insertions, 0 deletions
diff --git a/README.md b/README.md
new file mode 100644
index 00000000..58f3c3a1
--- /dev/null
+++ b/README.md
@@ -0,0 +1,9 @@
+chisel3 is a new FIRRTL based chisel
+
+the current backward incompatiabilities with chisel 2.x are:
+
+val wire = Bits(width = 15)
+
+is
+
+val wire = Wire(Bits(width = 15))
diff --git a/build.sbt b/build.sbt
new file mode 100644
index 00000000..6ea399a5
--- /dev/null
+++ b/build.sbt
@@ -0,0 +1,7 @@
+organization := "edu.berkeley.cs"
+
+version := "0.1"
+
+name := "Chisel"
+
+scalaVersion := "2.10.2"
diff --git a/src/main/scala/Backend.scala b/src/main/scala/Backend.scala
new file mode 100644
index 00000000..9b8bfb6d
--- /dev/null
+++ b/src/main/scala/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/Core.scala b/src/main/scala/Core.scala
new file mode 100644
index 00000000..7725d242
--- /dev/null
+++ b/src/main/scala/Core.scala
@@ -0,0 +1,1154 @@
+package Chisel
+import scala.collection.mutable.{ArrayBuffer, Stack, HashSet, HashMap}
+import java.lang.reflect.Modifier._
+import scala.math.max
+
+class GenSym {
+ var counter = -1
+ def next(name: String): String = {
+ counter += 1
+ name + "_" + counter
+ }
+}
+
+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.id) = mod
+ }
+ val modulez = new Stack[Module]()
+ def pushModule(mod: Module) {
+ modulez.push(mod)
+ }
+ 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.toArray)
+ }
+ 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 setRefForId(id: String, name: String, overwrite: Boolean = false) {
+ if (overwrite || !refmap.contains(id)) {
+ refmap(id) = Ref(name)
+ }
+ }
+
+ def setFieldForId(parentid: String, id: String, name: String) {
+ refmap(id) = Field(Alias(parentid), 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)
+ (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 AndOp = PrimOp("bit-and")
+ val OrOp = PrimOp("bit-or")
+ val BitAndOp = PrimOp("bit-and")
+ val BitOrOp = PrimOp("bit-or")
+ val BitXorOp = PrimOp("bit-xor")
+ val BitNotOp = PrimOp("bit-not")
+ val NotOp = 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 AndReduceOp = PrimOp("and-reduce")
+ val OrReduceOp = PrimOp("or-reduce")
+ val XorReduceOp = PrimOp("xor-reduce")
+}
+import PrimOp._
+
+abstract class Immediate {
+ def fullname: String
+ def name: String
+}
+
+case class Alias(val id: String) extends Immediate {
+ def fullname = getRefForId(id).fullname
+ def name = getRefForId(id).name
+}
+case class Ref(val name: String) extends Immediate {
+ def fullname = name
+}
+case class Field(val imm: Immediate, val name: String) extends Immediate {
+ def fullname = {
+ val imm_fullname = imm.fullname
+ if (imm_fullname == "this") name else imm_fullname + "." + name
+ }
+}
+case class Index(val imm: Immediate, val value: Int) extends Immediate {
+ def name = "." + value
+ def fullname = {
+ imm.fullname + "." + value
+ }
+}
+
+case class Port(val id: String, val dir: Direction, val kind: Type);
+
+abstract class Width;
+case class UnknownWidth() extends Width;
+case class IntWidth(val value: Int) extends Width;
+
+abstract class Type(val isFlip: Boolean);
+case class UnknownType(flip: Boolean) extends Type(flip);
+case class UIntType(val width: Width, flip: Boolean) extends Type(flip);
+case class SIntType(val width: Width, flip: Boolean) extends Type(flip);
+case class FloType(flip: Boolean) extends Type(flip);
+case class DblType(flip: Boolean) extends Type(flip);
+case class BundleType(val ports: Array[Port], flip: Boolean) extends Type(flip);
+case class VectorType(val size: Int, val kind: Type, flip: Boolean) extends Type(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 DefMInt(val id: String, val value: String, val width: Int) extends Definition;
+case class DefPrim(val id: String, val kind: Type, val op: PrimOp, val args: Array[Alias], val lits: Array[BigInt]) extends Definition;
+case class DefPrimPad(val id: String, val kind: Type, val op: PrimOp, val args: Array[Alias], val lits: Array[BigInt]) extends Definition;
+case class DefWire(val id: String, val kind: Type) extends Definition;
+case class DefRegister(val id: String, val kind: Type) extends Definition;
+case class DefMemory(val id: String, val kind: Type, val size: Int) extends Definition;
+case class DefAccessor(val id: String, val source: Alias, val direction: Direction, val index: Alias) extends Definition;
+case class DefInstance(val id: String, val module: String) extends Definition;
+case class Conditionally(val pred: Alias, val conseq: Command, val alt: Command) extends Command;
+case class Begin(val body: Array[Command]) extends Command();
+case class Connect(val loc: Alias, val exp: Alias) extends Command;
+case class ConnectPad(val loc: Alias, val exp: Alias) extends Command;
+case class ConnectInit(val loc: Alias, val exp: Alias) extends Command;
+case class ConnectInitIndex(val loc: Alias, val index: Int, val exp: Alias) 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 {
+ val id = genSym.next("id")
+ var isDef_ = false
+ def defd: this.type = {
+ isDef_ = true
+ this
+ }
+ def isDef = isDef_
+}
+
+abstract class Data(dirArg: Direction) extends Id {
+ val mod = modulez.top
+ def toType: Type
+ var isFlipVar = dirArg == INPUT
+ def isFlip = isFlipVar
+ def dir: Direction = if (isFlip) INPUT else OUTPUT
+ def setDir(dir: Direction) {
+ isFlipVar = (dir == INPUT)
+ }
+ 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.ref, other.ref))
+ def <>(other: Data) =
+ pushCommand(Connect(this.ref, other.ref))
+ def cloneType: this.type
+ def cloneTypeWidth(width: Int): this.type
+ def ref: Alias =
+ Alias(id)
+ def name = getRefForId(id).name
+ def debugName = mod.debugName + "." + name
+ def getWidth: Int
+ def flatten: Array[Bits]
+ def fromBits(n: Bits): this.type = {
+ val res = this.cloneType
+ var i = 0
+ val wire = Wire(res)
+ for (x <- wire.flatten.reverse) {
+ x := n(i + x.getWidth-1, i)
+ i += x.getWidth
+ }
+ res
+ }
+ def toBits: Bits = {
+ val elts = this.flatten
+ Cat(elts.head, elts.tail:_*)
+ }
+ def makeLit(value: BigInt, width: Int): this.type = {
+ val x = cloneType
+ x.fromBits(Bits(value, width))
+ x
+ }
+ def toBool(): Bool =
+ chiselCast(this){Bool()}
+
+ def toPort: Port = Port(id, dir, toType)
+ def collectElts: Unit
+ var isReg_ = false
+ def isReg = isReg_
+}
+
+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
+ x.collectElts
+ pushCommand(DefWire(x.defd.id, x.toType))
+ if (init != null)
+ pushCommand(Connect(x.ref, 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.id, x.toType))
+ if (init != null)
+ pushCommand(ConnectInit(x.ref, init.ref))
+ if (next != null)
+ pushCommand(ConnectPad(x.ref, next.ref))
+ 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.id, mt.toType, size))
+ mem
+ }
+}
+
+class Mem[T <: Data](val t: T, val size: Int) /* with VecLike[T] */ { // TODO: VECLIKE
+ def apply(idx: Bits): T = {
+ val x = t.cloneType
+ pushCommand(DefAccessor(x.defd.id, Alias(t.id), NO_DIR, idx.ref))
+ x
+ }
+}
+
+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))
+ vec.collectElts
+ val isDef = true || elts.head.isDef
+ if (vec.isReg)
+ throw new Exception("Vec of Reg Deprecated.")
+ if (isDef) {
+ pushCommand(DefWire(vec.defd.id, vec.toType))
+ var i = 0
+ for (elt <- elts) {
+ pushCommand(ConnectPad(vec(i).ref, elt.ref))
+ 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](val elts: Iterable[T], dirArg: Direction = NO_DIR) extends Aggregate(dirArg) with VecLike[T] {
+ val elt0 = elts.head
+ val self = new ArrayBuffer[T]()
+ self ++= elts
+ 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.id, Alias(id), NO_DIR, idx.ref))
+ x
+ }
+ def apply(idx: Int): T =
+ self(idx)
+ def toPorts: Array[Port] =
+ self.map(d => d.toPort).toArray
+ def toType: Type =
+ VectorType(self.size, elt0.toType, isFlipVar)
+ override def cloneType: this.type = {
+ val v = Vec(elt0.cloneType, self.size).asInstanceOf[this.type]
+ v.collectElts
+ v
+ }
+ def inits (f: (Int, T, (Int, T, T) => Unit) => Unit) = {
+ var i = 0
+ def doInit (index: Int, elt: T, init: T) =
+ pushCommand(ConnectInitIndex(elt.ref, index, init.ref))
+ for (d <- self) {
+ f(i, d, doInit)
+ i += 1;
+ }
+ }
+ override def flatten: Array[Bits] =
+ self.map(_.flatten).reduce(_ ++ _)
+ override def getWidth: Int =
+ flatten.map(_.getWidth).reduce(_ + _)
+
+ def collectElts: Unit = {
+ for (i <- 0 until self.size) {
+ val elt = self(i)
+ setIndexForId(id, elt.id, i)
+ elt.collectElts
+ }
+ }
+
+ def length: Int = self.size
+}
+
+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[T <: Bits](x: T): 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: => T): T = {
+ val x = gen
+ pushCommand(DefWire(x.defd.id, x.toType))
+ val b = i.toBits
+ pushCommand(Connect(x.ref, b.ref))
+ x
+ }
+}
+
+import Literal._
+
+class MInt(val value: String, val width: Int) extends Data(NO_DIR) {
+ def cloneTypeWidth(width: Int): this.type = cloneType
+ def collectElts: Unit = { }
+ override def dir: Direction = NO_DIR
+ override def setDir(dir: Direction): Unit = { }
+ override def toType: Type = UIntType(UnknownWidth(), isFlip)
+ override def getWidth: Int = width
+ override def flatten: Array[Bits] = Array[Bits](Bits(0))
+ override def cloneType: this.type =
+ new MInt(value, width).asInstanceOf[this.type]
+ def fromInt(x: BigInt): MInt = MInt(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 MInt {
+ def mintLit(value: String, width: Int) = new MInt(value, width)
+ def apply(value: String, width: Int) = mintLit(value, width)
+ def apply(value: String) = mintLit(value, -1)
+}
+
+abstract class Element(dirArg: Direction, val width: Int) extends Data(dirArg) {
+ def collectElts: Unit = { }
+ override def getWidth: Int = width
+}
+
+abstract class Bits(dirArg: Direction, width: Int) extends Element(dirArg, width) {
+ var litValue: Option[BigInt] = Some(-1)
+
+ def litValueGet: BigInt = litValue.getOrElse(-1)
+
+ override def flatten: Array[Bits] = Array[Bits](this)
+
+ def apply(x: UInt): Bool =
+ apply(x.litValueGet)
+
+ def apply(x: BigInt): Bool = {
+ val d = new Bool(dir)
+ pushCommand(DefPrim(d.defd.id, d.toType, BitSelectOp, Array(this.ref), Array(x)))
+ d
+ }
+ def apply(x: UInt, y: UInt): this.type =
+ apply(x.litValueGet, y.litValueGet)
+
+ def apply(x: BigInt, y: BigInt): this.type = {
+ val d = cloneTypeWidth(-1)
+ pushCommand(DefPrim(d.defd.id, d.toType, BitsExtractOp, Array(this.ref), Array(x, y)))
+ d
+ }
+
+ def :=(other: Bits) =
+ pushCommand(ConnectPad(this.ref, other.ref))
+
+ override def fromBits(n: Bits): this.type = {
+ val res = Wire(this.cloneType)
+ res := n
+ res.asInstanceOf[this.type]
+ }
+
+ private def bits_unop(op: PrimOp): Bits = {
+ val d = cloneTypeWidth(-1)
+ pushCommand(DefPrim(d.defd.id, d.toType, op, Array(this.ref), NoLits))
+ d
+ }
+ private def bits_binop(op: PrimOp, other: BigInt): Bits = {
+ val d = cloneTypeWidth(-1)
+ pushCommand(DefPrim(d.defd.id, d.toType, op, Array(this.ref), Array(other)))
+ d.asInstanceOf[Bits]
+ }
+ private def bits_binop_pad(op: PrimOp, other: Bits): Bits = {
+ val d = cloneTypeWidth(-1)
+ pushCommand(DefPrimPad(d.defd.id, d.toType, op, Array(this.ref, other.ref), NoLits))
+ d
+ }
+ private def bits_binop(op: PrimOp, other: Bits): Bits = {
+ val d = cloneTypeWidth(-1)
+ pushCommand(DefPrim(d.defd.id, d.toType, op, Array(this.ref, other.ref), NoLits))
+ d
+ }
+ private def bits_compop_pad(op: PrimOp, other: Bits): Bool = {
+ val d = new Bool(dir)
+ pushCommand(DefPrimPad(d.defd.id, d.toType, op, Array(this.ref, other.ref), NoLits))
+ d
+ }
+
+ def unary_- = bits_unop(NegOp)
+ def + (other: Bits) = bits_binop_pad(AddOp, other)
+ def +% (other: Bits) = bits_binop_pad(AddModOp, other)
+ def - (other: Bits) = bits_binop_pad(SubOp, other)
+ def -% (other: Bits) = bits_binop_pad(SubModOp, other)
+ def * (other: Bits) = bits_binop_pad(TimesOp, other)
+ def / (other: Bits) = bits_binop_pad(DivideOp, other)
+ def % (other: Bits) = bits_binop_pad(ModOp, other)
+ def << (other: BigInt) = bits_binop(ShiftLeftOp, other)
+ def << (other: Bits) = bits_binop(DynamicShiftLeftOp, other)
+ def >> (other: BigInt) = bits_binop(ShiftRightOp, other)
+ def >> (other: Bits) = bits_binop(DynamicShiftRightOp, other)
+ def unary_~(): Bits = bits_unop(BitNotOp)
+
+ def & (other: Bits) = bits_binop_pad(BitAndOp, other)
+ def | (other: Bits) = bits_binop_pad(BitOrOp, other)
+ def ^ (other: Bits) = bits_binop_pad(BitXorOp, other)
+
+ def < (other: Bits) = bits_compop_pad(LessOp, other)
+ def > (other: Bits) = bits_compop_pad(GreaterOp, other)
+ def === (other: Bits) = bits_compop_pad(EqualOp, other)
+ def !== (other: Bits) = bits_compop_pad(NotEqualOp, other)
+ def <= (other: Bits) = bits_compop_pad(LessEqOp, other)
+ def >= (other: Bits) = bits_compop_pad(GreaterEqOp, other)
+ def pad (other: BigInt) = bits_binop(PadOp, other)
+
+ private def bits_redop(op: PrimOp): Bool = {
+ val d = new Bool(dir)
+ pushCommand(DefPrim(d.defd.id, d.toType, op, Array(this.ref), NoLits))
+ d
+ }
+
+ def orR = bits_redop(OrReduceOp)
+ def andR = bits_redop(AndReduceOp)
+ def xorR = bits_redop(XorReduceOp)
+
+ def bitSet(off: BigInt, 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 fromInt(x: BigInt): this.type;
+
+ def toSInt(): SInt = chiselCast(this){SInt()};
+
+ def toUInt(): UInt = chiselCast(this){UInt()};
+}
+
+import UInt._
+
+object Bits {
+ def apply(dir: Direction = OUTPUT, width: Int = -1) = new UInt(dir, width)
+ def apply(value: BigInt, width: Int) = uintLit(value, width)
+ def apply(value: BigInt) = uintLit(value, -1)
+}
+
+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]
+ override def cloneType : this.type = cloneTypeWidth(width)
+
+ def toType: Type =
+ UIntType(if (width == -1) UnknownWidth() else IntWidth(width), isFlipVar)
+
+ def fromInt(x: BigInt): this.type = UInt(x).asInstanceOf[this.type]
+
+ override def makeLit(value: BigInt, width: Int): this.type =
+ UInt(value, width).asInstanceOf[this.type]
+
+ private def uint_unop(op: PrimOp): UInt = {
+ val d = cloneTypeWidth(-1)
+ pushCommand(DefPrim(d.defd.id, d.toType, op, Array(this.ref), NoLits))
+ d
+ }
+ private def uint_binop(op: PrimOp, other: UInt): UInt = {
+ val d = cloneTypeWidth(-1)
+ pushCommand(DefPrim(d.defd.id, d.toType, op, Array(this.ref, other.ref), NoLits))
+ d
+ }
+ private def uint_binop_pad(op: PrimOp, other: UInt): UInt = {
+ val d = cloneTypeWidth(-1)
+ pushCommand(DefPrimPad(d.defd.id, d.toType, op, Array(this.ref, other.ref), NoLits))
+ d
+ }
+ private def uint_binop(op: PrimOp, other: BigInt): UInt = {
+ val d = cloneTypeWidth(-1)
+ pushCommand(DefPrim(d.defd.id, d.toType, op, Array(this.ref), Array(other)))
+ d
+ }
+ private def uint_compop_pad(op: PrimOp, other: UInt): Bool = {
+ val d = new Bool(dir)
+ pushCommand(DefPrimPad(d.defd.id, d.toType, op, Array(this.ref, other.ref), NoLits))
+ d
+ }
+
+ override def unary_- = uint_unop(NegOp)
+ def + (other: UInt) = uint_binop_pad(AddOp, other)
+ def +% (other: UInt) = uint_binop_pad(AddModOp, other)
+ def - (other: UInt) = uint_binop_pad(SubOp, other)
+ def -% (other: UInt) = uint_binop_pad(SubModOp, other)
+ def * (other: UInt) = uint_binop_pad(TimesOp, other)
+ def / (other: UInt) = uint_binop_pad(DivideOp, other)
+ def % (other: UInt) = uint_binop_pad(ModOp, other)
+ override def << (other: BigInt) = uint_binop(ShiftLeftOp, other)
+ def << (other: UInt) = uint_binop(DynamicShiftLeftOp, other)
+ override def >> (other: BigInt) = uint_binop(ShiftRightOp, other)
+ def >> (other: UInt) = uint_binop(DynamicShiftRightOp, other)
+
+ override def unary_~(): UInt = uint_unop(BitNotOp)
+ def & (other: UInt) = uint_binop_pad(BitAndOp, other)
+ def | (other: UInt) = uint_binop_pad(BitOrOp, other)
+ def ^ (other: UInt) = uint_binop_pad(BitXorOp, other)
+
+ def < (other: UInt) = uint_compop_pad(LessOp, other)
+ def > (other: UInt) = uint_compop_pad(GreaterOp, other)
+ def === (other: UInt) = uint_compop_pad(EqualOp, other)
+ def !== (other: UInt) = uint_compop_pad(NotEqualOp, other)
+ def <= (other: UInt) = uint_compop_pad(LessEqOp, other)
+ def >= (other: UInt) = uint_compop_pad(GreaterEqOp, other)
+
+ override def pad (other: BigInt) = uint_binop(PadOp, other)
+}
+
+object UInt {
+ def apply(dir: Direction = OUTPUT, width: Int = -1) =
+ new UInt(dir, width)
+ def uintLit(value: BigInt, width: Int) = {
+ val w = if(width == -1) max(bitLength(value), 1) else width
+ val b = new UInt(NO_DIR, w)
+ pushCommand(DefUInt(b.defd.id, value, w))
+ b
+ }
+ def apply(value: BigInt, width: Int) = uintLit(value, width)
+ def apply(value: BigInt) = uintLit(value, -1)
+}
+
+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]
+ override def cloneType: this.type = cloneTypeWidth(width)
+ def toType: Type =
+ SIntType(if (width == -1) UnknownWidth() else IntWidth(width), isFlipVar)
+
+ def fromInt(x: BigInt): this.type = SInt(x).asInstanceOf[this.type]
+
+ override def makeLit(value: BigInt, width: Int): this.type =
+ SInt(value, width).asInstanceOf[this.type]
+
+ private def sint_unop(op: PrimOp): SInt = {
+ val d = cloneTypeWidth(-1)
+ pushCommand(DefPrim(d.defd.id, d.toType, op, Array(this.ref), NoLits))
+ d
+ }
+ private def sint_binop(op: PrimOp, other: BigInt): Bits = {
+ val d = cloneTypeWidth(-1)
+ pushCommand(DefPrim(d.defd.id, d.toType, op, Array(this.ref), Array(other)))
+ d
+ }
+ private def sint_binop(op: PrimOp, other: Bits): SInt = {
+ val d = cloneTypeWidth(-1)
+ pushCommand(DefPrim(d.defd.id, d.toType, op, Array(this.ref, other.ref), NoLits))
+ d
+ }
+ private def sint_binop_pad(op: PrimOp, other: SInt): SInt = {
+ val d = cloneTypeWidth(-1)
+ pushCommand(DefPrimPad(d.defd.id, d.toType, op, Array(this.ref, other.ref), NoLits))
+ d
+ }
+ private def sint_compop_pad(op: PrimOp, other: SInt): Bool = {
+ val d = new Bool(dir)
+ pushCommand(DefPrimPad(d.defd.id, d.toType, op, Array(this.ref, other.ref), NoLits))
+ d
+ }
+
+ override def unary_- = sint_unop(NegOp)
+ def + (other: SInt) = sint_binop_pad(AddOp, other)
+ def +% (other: SInt) = sint_binop_pad(AddModOp, other)
+ def - (other: SInt) = sint_binop_pad(SubOp, other)
+ def -% (other: SInt) = sint_binop_pad(SubModOp, other)
+ def * (other: SInt) = sint_binop_pad(TimesOp, other)
+ def / (other: SInt) = sint_binop_pad(DivideOp, other)
+ def % (other: SInt) = sint_binop_pad(ModOp, other)
+ override def << (other: BigInt) = sint_binop(ShiftLeftOp, other)
+ def << (other: UInt) = sint_binop(DynamicShiftLeftOp, other)
+ override def >> (other: BigInt) = sint_binop(ShiftRightOp, other)
+ def >> (other: UInt) = sint_binop(DynamicShiftRightOp, other)
+
+ override def unary_~(): SInt = sint_unop(BitNotOp)
+ def & (other: SInt) = sint_binop_pad(BitAndOp, other)
+ def | (other: SInt) = sint_binop_pad(BitOrOp, other)
+ def ^ (other: SInt) = sint_binop_pad(BitXorOp, other)
+
+ def < (other: SInt) = sint_compop_pad(LessOp, other)
+ def > (other: SInt) = sint_compop_pad(GreaterOp, other)
+ def === (other: SInt) = sint_compop_pad(EqualOp, other)
+ def !== (other: SInt) = sint_compop_pad(NotEqualOp, other)
+ def <= (other: SInt) = sint_compop_pad(LessEqOp, other)
+ def >= (other: SInt) = sint_compop_pad(GreaterEqOp, other)
+
+ override def pad (other: BigInt) = sint_binop(PadOp, other)
+}
+
+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)
+ pushCommand(DefSInt(b.defd.id, value, w))
+ b
+ }
+ def apply(value: BigInt, width: Int) = sintLit(value, width)
+ def apply(value: BigInt) = sintLit(value, -1)
+}
+
+class Bool(dir: Direction) extends UInt(dir, 1) {
+ override def cloneTypeWidth(w: Int): this.type = new Bool(dir).asInstanceOf[this.type]
+ override def cloneType: this.type = cloneTypeWidth(1)
+
+ override def fromInt(x: BigInt): this.type = Bool(x).asInstanceOf[this.type]
+
+ override def makeLit(value: BigInt, width: Int): this.type =
+ Bool(value).asInstanceOf[this.type]
+
+ def || (other: Bool) = {
+ val d = new Bool(dir)
+ pushCommand(DefPrim(d.defd.id, d.toType, OrOp, Array(this.ref, other.ref), NoLits))
+ d
+ }
+ def && (other: Bool) = {
+ val d = new Bool(dir)
+ pushCommand(DefPrim(d.defd.id, d.toType, AndOp, Array(this.ref, other.ref), NoLits))
+ d
+ }
+ def unary_! (): Bool = {
+ val d = new Bool(dir)
+ pushCommand(DefPrim(d.defd.id, d.toType, NotOp, Array(this.ref), NoLits))
+ d
+ }
+}
+object Bool {
+ def apply(dir: Direction) : Bool =
+ new Bool(dir)
+ def apply() : Bool =
+ apply(NO_DIR)
+ def apply(value: BigInt) : Bool = {
+ val b = new Bool(NO_DIR)
+ pushCommand(DefUInt(b.defd.id, value, 1))
+ b
+ }
+ 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 r = con.cloneTypeWidth(-1)
+ val args = Array(cond.ref, con.ref, alt.ref)
+ con match {
+ case t: Bits =>
+ pushCommand(DefPrimPad(r.defd.id, r.toType, MultiplexOp, args, NoLits))
+ case _ =>
+ pushCommand(DefPrim(r.defd.id, r.toType, MultiplexOp, args, NoLits))
+ }
+ r.asInstanceOf[T]
+ }
+}
+
+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 d = l.cloneType
+ pushCommand(DefPrim(d.id, 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", "toUInt", "toBits",
+ "toBool", "toSInt", "asDirectionless")
+}
+
+class Bundle(dirArg: Direction = NO_DIR) extends Aggregate(dirArg) {
+ def toPorts: Array[Port] =
+ elts.map(d => d.toPort).toArray
+ def toType: BundleType =
+ BundleType(this.toPorts, isFlipVar)
+
+ override def flatten: Array[Bits] =
+ elts.map(_.flatten).reduce(_ ++ _)
+ override def getWidth: Int =
+ flatten.map(_.getWidth).reduce(_ + _)
+
+ val elts = ArrayBuffer[Data]()
+ def collectElts: Unit = {
+ elts.clear()
+ for (m <- getClass.getDeclaredMethods) {
+ val name = m.getName
+
+ val modifiers = m.getModifiers();
+ val types = m.getParameterTypes()
+ var isInterface = false;
+ var isFound = false;
+ val rtype = m.getReturnType();
+ var c = rtype;
+ val sc = Class.forName("Chisel.Data");
+ do {
+ if (c == sc) {
+ isFound = true; isInterface = true;
+ } else if (c == null || c == Class.forName("java.lang.Object")) {
+ isFound = true; isInterface = false;
+ } else {
+ c = c.getSuperclass();
+ }
+ } while (!isFound);
+ if (types.length == 0 && !isStatic(modifiers) && isInterface
+ && !(Bundle.keywords contains name)) {
+ val obj = m.invoke(this)
+ obj match {
+ case data: Data =>
+ setFieldForId(id, data.id, name)
+ data.collectElts
+ elts += data
+ case _ => ()
+ }
+ }
+ }
+
+ elts.sortWith { (a, b) => a.id < b.id }
+ }
+
+ override def cloneType: this.type = {
+ try {
+ val constructor = this.getClass.getConstructors.head
+ val res = constructor.newInstance(Array.fill(constructor.getParameterTypes.size)(null):_*)
+ val rest = res.asInstanceOf[this.type]
+ rest.collectElts
+ rest
+ } catch {
+ case npe: java.lang.reflect.InvocationTargetException if npe.getCause.isInstanceOf[java.lang.NullPointerException] =>
+ // throwException("Parameterized Bundle " + this.getClass + " needs clone method. You are probably using an anonymous Bundle object that captures external state and hence is un-cloneable", npe)
+ error("BAD")
+ case e: java.lang.Exception =>
+ error("BAD")
+ // throwException("Parameterized Bundle " + this.getClass + " needs clone method", e)
+ }
+ }
+}
+
+object Module {
+ def apply[T <: Module](c: T): T = {
+ val cmd = popCommands
+ popScope
+ popModule
+ c.io.collectElts
+ c.setRefs
+ val ports = c.io.toPorts
+ val component = UniqueComponent(c.name, ports, cmd)
+ components += component
+ pushCommand(DefInstance(c.defd.id, component.name))
+ c
+ }
+}
+
+abstract class Module extends Id {
+ val parent = modulez.headOption
+ pushModule(this)
+ pushScope
+ pushCommands
+ addModule(this)
+
+ def io: Bundle
+ def ref = getRefForId(id)
+ val reset = Bool().defd
+ setRefForId(reset.id, "reset")
+
+ def name = {
+ // getClass.getName.replace('.', '_')
+ getClass.getName.split('.').last
+ }
+ def debugName: String = {
+ val p = parent.getOrElse(null)
+ name + (if (p == null) "" else ("__" + p.debugName))
+ }
+
+ def setRefs {
+ setRefForId(io.id, "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.id, name)
+ module.setRefs
+ case bundle: Bundle =>
+ if (name != "io") {
+ setRefForId(bundle.id, name)
+ }
+ case mem: Mem[_] =>
+ setRefForId(mem.t.id, name)
+ case vec: Vec[_] =>
+ setRefForId(vec.id, name)
+ case data: Data =>
+ setRefForId(data.id, name)
+ // ignore anything not of those types
+ case _ => null
+ }
+ }
+ }
+ }
+}
+
+object when {
+ def execBlock(block: => Unit): Command = {
+ pushScope
+ pushCommands
+ block
+ val cmd = popCommands
+ popScope
+ cmd
+ }
+ def execWhen(cond: => Bool)(block: => Unit) {
+ val pred = cond.ref
+ val cmd = execBlock(block)
+ pushCommand(Conditionally(pred, cmd, EmptyCommand()))
+ }
+ def apply(cond: => Bool)(block: => Unit): when = {
+ execWhen(cond){ block }
+ new when
+ }
+}
+
+import when._
+
+class when {
+ def elsewhen (cond: => Bool)(block: => Unit): when = {
+ this.otherwise {
+ when.execWhen(cond) { block }
+ }
+ new when
+ }
+
+ private def replaceCondition(cond: Conditionally, elsecmd: Command): Conditionally = {
+ cond.alt match {
+ // this is an elsewhen clause
+ // we have to go deeper
+ case newcond: Conditionally =>
+ Conditionally(cond.pred, cond.conseq,
+ replaceCondition(newcond, elsecmd))
+ // if the alt is empty, we've found the end
+ case empty: EmptyCommand =>
+ Conditionally(cond.pred, cond.conseq, elsecmd)
+ // this shouldn't happen
+ case _ =>
+ throw new Exception("Cannot replace non-empty else clause")
+ }
+ }
+
+ def otherwise (block: => Unit) {
+ // first generate the body
+ val elsecmd = execBlock(block)
+ // now we look back and find the last Conditionally
+ val isConditionally = (x: Command) => {
+ x match {
+ case Conditionally(_, _, _) => true
+ case _ => false
+ }
+ }
+ // replace the last Conditionally with a new one with the
+ // same predicate and consequent but with the last alt replaced
+ // by the commands for the otherwise body
+ val i = commands.lastIndexWhere(isConditionally)
+ commands(i) = commands(i) match {
+ case cond: Conditionally =>
+ replaceCondition(cond, elsecmd)
+ // this should never happen
+ case _ => throw new Exception("That's not a conditionally")
+ }
+ }
+}
+
+
+/// 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 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: Alias): 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: Type): 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 = {
+ e match {
+ case e: DefUInt => "node " + e.name + " = UInt(" + e.value + (if (e.width == -1) "" else ", " + e.width) + ")"
+ case e: DefSInt => "node " + e.name + " = SInt(" + e.value + (if (e.width == -1) "" else ", " + e.width) + ")"
+ 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: DefPrimPad => "node " + e.name + " = " + emit(e.op) + "(" + join(e.args.map(x => "Pad(" + 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 => "mem " + e.name + " : " + emitType(e.kind) + "[" + e.size + "]";
+ // case e: DefVector => "vec " + e.name + " : " + emit(e.kind) + "(" + join(e.args.map(x => emit(x)).toArray[String], " ") + ")"
+ 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.id, e.name, true)
+ "inst " + e.name + " of " + e.module
+ }
+ case e: Conditionally => "when " + emit(e.pred) + " : " + withIndent{ emit(e.conseq) } + (if (e.alt.isInstanceOf[EmptyCommand]) "" else newline + "else : " + withIndent{ emit(e.alt) })
+ case e: Begin => join0(e.body.map(x => emit(x)), newline)
+ case e: Connect => emit(e.loc) + " := " + emit(e.exp)
+ case e: ConnectPad => emit(e.loc) + " := Pad(" + emit(e.exp) + ",?)"
+ case e: ConnectInit => emit(e.loc) + ".init := Pad(" + emit(e.exp) + ",?)"
+ case e: ConnectInitIndex => emit(e.loc) + ".init." + e.index + " := Pad(" + 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/Driver.scala b/src/main/scala/Driver.scala
new file mode 100644
index 00000000..1f3f49b8
--- /dev/null
+++ b/src/main/scala/Driver.scala
@@ -0,0 +1,421 @@
+/*
+ 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 {
+ 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): T = {
+ if (!chiselConfigMode.isEmpty && !chiselConfigClassName.isEmpty) {
+ 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 c = 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
+ }
+ c
+ }
+ else {
+ execute(() => Module(gen()))
+ }
+ }
+ */
+
+ private def execute[T <: Module](gen: () => T): (Circuit, T) = {
+ val emitter = new Emitter
+ val (c, mod) = build{ Module(gen()) }
+ val s = emitter.emit( c )
+ 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") {
+ setTopComponent(c)
+ backend.elaborate(c)
+ if (isCompiling && isGenHarness) backend.compile(c)
+ 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/Enum.scala b/src/main/scala/Enum.scala
new file mode 100644
index 00000000..3bc24220
--- /dev/null
+++ b/src/main/scala/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/Error.scala b/src/main/scala/Error.scala
new file mode 100644
index 00000000..1ad5414d
--- /dev/null
+++ b/src/main/scala/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/FP.scala b/src/main/scala/FP.scala
new file mode 100644
index 00000000..5f6cf579
--- /dev/null
+++ b/src/main/scala/FP.scala
@@ -0,0 +1,319 @@
+/*
+ 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)
+ pushCommand(DefFlo(b.defd.id, 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) extends Element(dir, 32) with Num[Flo] {
+ type T = Flo;
+ def cloneTypeWidth(width: Int): this.type = cloneType
+ override def fromBits(n: Bits): this.type = {
+ val d = cloneType
+ pushCommand(DefPrim(d.defd.id, d.toType, BitsToFlo, Array(this.ref), NoLits))
+ d
+ }
+ override def toBits: Bits = {
+ val d = new UInt(dir, 32)
+ pushCommand(DefPrim(d.defd.id, d.toType, FloToBits, Array(this.ref), NoLits))
+ d
+ }
+ def toType: Type = FloType(isFlip)
+ def cloneType: this.type = new Flo(dir).asInstanceOf[this.type]
+ def flatten: Array[Bits] = Array[Bits](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.id, d.toType, op, Array(this.ref), NoLits))
+ d
+ }
+ private def flo_binop(op: PrimOp, other: Flo): Flo = {
+ val d = cloneType
+ pushCommand(DefPrim(d.defd.id, 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.id, 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)
+ pushCommand(DefDbl(b.defd.id, 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 = null) extends Element(dir, 64) with Num[Dbl] {
+ // setIsSigned
+
+ // override def setIsTypeNode = {inputs(0).setIsSigned; super.setIsTypeNode}
+
+ type T = Dbl;
+ def cloneTypeWidth(width: Int): this.type = cloneType
+ override def fromBits(n: Bits): this.type = {
+ val d = cloneType
+ pushCommand(DefPrim(d.defd.id, d.toType, BitsToDbl, Array(this.ref), NoLits))
+ d
+ }
+ override def toBits: Bits = {
+ val d = new UInt(dir, 64)
+ pushCommand(DefPrim(d.defd.id, d.toType, DblToBits, Array(this.ref), NoLits))
+ d
+ }
+ def toType: Type = DblType(isFlip)
+ def cloneType: this.type = new Dbl(dir).asInstanceOf[this.type]
+ def flatten: Array[Bits] = Array[Bits](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.id, d.toType, op, Array(this.ref), NoLits))
+ d
+ }
+ private def dbl_binop(op: PrimOp, other: Dbl): Dbl = {
+ val d = cloneType
+ pushCommand(DefPrim(d.defd.id, 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.id, 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/Literal.scala b/src/main/scala/Literal.scala
new file mode 100644
index 00000000..fff2780b
--- /dev/null
+++ b/src/main/scala/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/Tester.scala b/src/main/scala/Tester.scala
new file mode 100644
index 00000000..fc55fc53
--- /dev/null
+++ b/src/main/scala/Tester.scala
@@ -0,0 +1,389 @@
+/*
+ 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 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: Data, 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: Aggregate /*, off: Int = -1 */): Array[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: Data, 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: 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.getOrElse(-1)
+
+ 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 + " <- " + got + " == " + expected)
+ }
+
+ 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))
+ }
+
+ /* 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/utils.scala b/src/main/scala/utils.scala
new file mode 100644
index 00000000..346ce657
--- /dev/null
+++ b/src/main/scala/utils.scala
@@ -0,0 +1,253 @@
+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: Bits): Bits = apply(n, in.toBools)
+ def apply(n: Int, in: Seq[Bool]): Bits = 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(key === k, 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[(UInt, 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[(UInt, 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)
+}