summaryrefslogtreecommitdiff
path: root/src/main/scala/Core.scala
diff options
context:
space:
mode:
authorjackbackrack2015-04-27 15:58:20 -0700
committerjackbackrack2015-04-27 15:58:20 -0700
commit136352557ba0c6b9c97621e9dfefb4009faef7cc (patch)
tree0d4b04d90e5efd95b04e02bfd7c8c5e1cc210b8c /src/main/scala/Core.scala
first commit
Diffstat (limited to 'src/main/scala/Core.scala')
-rw-r--r--src/main/scala/Core.scala1154
1 files changed, 1154 insertions, 0 deletions
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) }
+}