summaryrefslogtreecommitdiff
path: root/chiselFrontend
diff options
context:
space:
mode:
authorducky2016-05-05 11:50:39 -0700
committerducky2016-05-05 11:50:39 -0700
commit9036d96bb032c19de31131f2296120e708cbc3dc (patch)
treecf17173fab309b09670ca7529680e09d61341451 /chiselFrontend
parent623a301df1f5a1954f8e4a64ef97c99c3900da28 (diff)
Move Chisel API into separate chiselFrontend compilation unit in preparation for source locator macros
Diffstat (limited to 'chiselFrontend')
-rw-r--r--chiselFrontend/src/main/scala/Chisel/Aggregate.scala342
-rw-r--r--chiselFrontend/src/main/scala/Chisel/BitPat.scala80
-rw-r--r--chiselFrontend/src/main/scala/Chisel/Bits.scala571
-rw-r--r--chiselFrontend/src/main/scala/Chisel/BlackBox.scala54
-rw-r--r--chiselFrontend/src/main/scala/Chisel/CoreUtil.scala97
-rw-r--r--chiselFrontend/src/main/scala/Chisel/Data.scala152
-rw-r--r--chiselFrontend/src/main/scala/Chisel/Mem.scala123
-rw-r--r--chiselFrontend/src/main/scala/Chisel/Module.scala103
-rw-r--r--chiselFrontend/src/main/scala/Chisel/Reg.scala66
-rw-r--r--chiselFrontend/src/main/scala/Chisel/SeqUtils.scala47
-rw-r--r--chiselFrontend/src/main/scala/Chisel/When.scala56
-rw-r--r--chiselFrontend/src/main/scala/Chisel/internal/Builder.scala122
-rw-r--r--chiselFrontend/src/main/scala/Chisel/internal/Error.scala91
-rw-r--r--chiselFrontend/src/main/scala/Chisel/internal/firrtl/Emitter.scala101
-rw-r--r--chiselFrontend/src/main/scala/Chisel/internal/firrtl/IR.scala187
15 files changed, 2192 insertions, 0 deletions
diff --git a/chiselFrontend/src/main/scala/Chisel/Aggregate.scala b/chiselFrontend/src/main/scala/Chisel/Aggregate.scala
new file mode 100644
index 00000000..4d35e2f0
--- /dev/null
+++ b/chiselFrontend/src/main/scala/Chisel/Aggregate.scala
@@ -0,0 +1,342 @@
+// See LICENSE for license details.
+
+package Chisel
+
+import scala.collection.immutable.ListMap
+import scala.collection.mutable.{ArrayBuffer, HashSet, LinkedHashMap}
+
+import internal._
+import internal.Builder.pushCommand
+import internal.firrtl._
+
+/** An abstract class for data types that solely consist of (are an aggregate
+ * of) other Data objects.
+ */
+sealed abstract class Aggregate(dirArg: Direction) extends Data(dirArg) {
+ private[Chisel] def cloneTypeWidth(width: Width): this.type = cloneType
+ def width: Width = flatten.map(_.width).reduce(_ + _)
+}
+
+object Vec {
+ /** Creates a new [[Vec]] with `n` entries of the specified data type.
+ *
+ * @note elements are NOT assigned by default and have no value
+ */
+ def apply[T <: Data](n: Int, gen: T): Vec[T] = new Vec(gen.cloneType, n)
+
+ @deprecated("Vec argument order should be size, t; this will be removed by the official release", "chisel3")
+ def apply[T <: Data](gen: T, n: Int): Vec[T] = new Vec(gen.cloneType, n)
+
+ /** Creates a new [[Vec]] composed of elements of the input Seq of [[Data]]
+ * nodes.
+ *
+ * @note input elements should be of the same type (this is checked at the
+ * FIRRTL level, but not at the Scala / Chisel level)
+ * @note the width of all output elements is the width of the largest input
+ * element
+ * @note output elements are connected from the input elements
+ */
+ def apply[T <: Data](elts: Seq[T]): Vec[T] = {
+ // REVIEW TODO: this should be removed in favor of the apply(elts: T*)
+ // varargs constructor, which is more in line with the style of the Scala
+ // collection API. However, a deprecation phase isn't possible, since
+ // changing apply(elt0, elts*) to apply(elts*) causes a function collision
+ // with apply(Seq) after type erasure. Workarounds by either introducing a
+ // DummyImplicit or additional type parameter will break some code.
+
+ require(!elts.isEmpty)
+ val width = elts.map(_.width).reduce(_ max _)
+ val vec = Wire(new Vec(elts.head.cloneTypeWidth(width), elts.length))
+ for ((v, e) <- vec zip elts)
+ v := e
+ vec
+ }
+
+ /** Creates a new [[Vec]] composed of the input [[Data]] nodes.
+ *
+ * @note input elements should be of the same type (this is checked at the
+ * FIRRTL level, but not at the Scala / Chisel level)
+ * @note the width of all output elements is the width of the largest input
+ * element
+ * @note output elements are connected from the input elements
+ */
+ def apply[T <: Data](elt0: T, elts: T*): Vec[T] =
+ apply(elt0 +: elts.toSeq)
+
+ /** Creates a new [[Vec]] of length `n` composed of the results of the given
+ * function applied over a range of integer values starting from 0.
+ *
+ * @param n number of elements in the vector (the function is applied from
+ * 0 to `n-1`)
+ * @param gen function that takes in an Int (the index) and returns a
+ * [[Data]] that becomes the output element
+ */
+ def tabulate[T <: Data](n: Int)(gen: (Int) => T): Vec[T] =
+ apply((0 until n).map(i => gen(i)))
+
+ /** Creates a new [[Vec]] of length `n` composed of the result of the given
+ * function repeatedly applied.
+ *
+ * @param n number of elements (amd the number of times the function is
+ * called)
+ * @param gen function that generates the [[Data]] that becomes the output
+ * element
+ */
+ def fill[T <: Data](n: Int)(gen: => T): Vec[T] = apply(Seq.fill(n)(gen))
+}
+
+/** A vector (array) of [[Data]] elements. Provides hardware versions of various
+ * collection transformation functions found in software array implementations.
+ *
+ * @tparam T type of elements
+ * @note when multiple conflicting assignments are performed on a Vec element,
+ * the last one takes effect (unlike Mem, where the result is undefined)
+ * @note Vecs, unlike classes in Scala's collection library, are propagated
+ * intact to FIRRTL as a vector type, which may make debugging easier
+ */
+sealed class Vec[T <: Data] private (gen: => T, val length: Int)
+ extends Aggregate(gen.dir) with VecLike[T] {
+ // Note: the constructor takes a gen() function instead of a Seq to enforce
+ // that all elements must be the same and because it makes FIRRTL generation
+ // simpler.
+
+ private val self = IndexedSeq.fill(length)(gen)
+
+ override def <> (that: Data): Unit = this := that
+
+ /** Strong bulk connect, assigning elements in this Vec from elements in a Seq.
+ *
+ * @note the length of this Vec must match the length of the input Seq
+ */
+ def <> (that: Seq[T]): Unit = this := that
+
+ // TODO: eliminate once assign(Seq) isn't ambiguous with assign(Data) since Vec extends Seq and Data
+ def <> (that: Vec[T]): Unit = this := that.asInstanceOf[Data]
+
+ override def := (that: Data): Unit = that match {
+ case _: Vec[_] => this connect that
+ case _ => this badConnect that
+ }
+
+ /** Strong bulk connect, assigning elements in this Vec from elements in a Seq.
+ *
+ * @note the length of this Vec must match the length of the input Seq
+ */
+ def := (that: Seq[T]): Unit = {
+ require(this.length == that.length)
+ for ((a, b) <- this zip that)
+ a := b
+ }
+
+ // TODO: eliminate once assign(Seq) isn't ambiguous with assign(Data) since Vec extends Seq and Data
+ def := (that: Vec[T]): Unit = this connect that
+
+ /** Creates a dynamically indexed read or write accessor into the array.
+ */
+ def apply(idx: UInt): T = {
+ val x = gen
+ x.setRef(this, idx)
+ x
+ }
+
+ /** Creates a statically indexed read or write accessor into the array.
+ */
+ def apply(idx: Int): T = self(idx)
+
+ @deprecated("Use Vec.apply instead", "chisel3")
+ def read(idx: UInt): T = apply(idx)
+
+ @deprecated("Use Vec.apply instead", "chisel3")
+ def write(idx: UInt, data: T): Unit = apply(idx) := data
+
+ override def cloneType: this.type =
+ Vec(length, gen).asInstanceOf[this.type]
+
+ private val t = gen
+ private[Chisel] def toType: String = s"${t.toType}[$length]"
+ private[Chisel] lazy val flatten: IndexedSeq[Bits] =
+ (0 until length).flatMap(i => this.apply(i).flatten)
+
+ for ((elt, i) <- self zipWithIndex)
+ elt.setRef(this, i)
+}
+
+/** A trait for [[Vec]]s containing common hardware generators for collection
+ * operations.
+ */
+trait VecLike[T <: Data] extends collection.IndexedSeq[T] {
+ def apply(idx: UInt): T
+
+ @deprecated("Use Vec.apply instead", "chisel3")
+ def read(idx: UInt): T
+
+ @deprecated("Use Vec.apply instead", "chisel3")
+ def write(idx: UInt, data: T): Unit
+
+ /** Outputs true if p outputs true for every element.
+ */
+ def forall(p: T => Bool): Bool = (this map p).fold(Bool(true))(_ && _)
+
+ /** Outputs true if p outputs true for at least one element.
+ */
+ def exists(p: T => Bool): Bool = (this map p).fold(Bool(false))(_ || _)
+
+ /** Outputs true if the vector contains at least one element equal to x (using
+ * the === operator).
+ */
+ def contains(x: T)(implicit evidence: T <:< UInt): Bool = this.exists(_ === x)
+
+ /** Outputs the number of elements for which p is true.
+ */
+ def count(p: T => Bool): UInt = SeqUtils.count(this map p)
+
+ /** Helper function that appends an index (literal value) to each element,
+ * useful for hardware generators which output an index.
+ */
+ private def indexWhereHelper(p: T => Bool) = this map p zip (0 until length).map(i => UInt(i))
+
+ /** Outputs the index of the first element for which p outputs true.
+ */
+ def indexWhere(p: T => Bool): UInt = SeqUtils.priorityMux(indexWhereHelper(p))
+
+ /** Outputs the index of the last element for which p outputs true.
+ */
+ def lastIndexWhere(p: T => Bool): UInt = SeqUtils.priorityMux(indexWhereHelper(p).reverse)
+
+ /** Outputs the index of the element for which p outputs true, assuming that
+ * the there is exactly one such element.
+ *
+ * The implementation may be more efficient than a priority mux, but
+ * incorrect results are possible if there is not exactly one true element.
+ *
+ * @note the assumption that there is only one element for which p outputs
+ * true is NOT checked (useful in cases where the condition doesn't always
+ * hold, but the results are not used in those cases)
+ */
+ def onlyIndexWhere(p: T => Bool): UInt = SeqUtils.oneHotMux(indexWhereHelper(p))
+}
+
+/** Base class for data types defined as a bundle of other data types.
+ *
+ * Usage: extend this class (either as an anonymous or named class) and define
+ * members variables of [[Data]] subtypes to be elements in the Bundle.
+ */
+class Bundle extends Aggregate(NO_DIR) {
+ private val _namespace = Builder.globalNamespace.child
+
+ // TODO: replace with better defined FIRRTL weak-connect operator
+ /** Connect elements in this Bundle to elements in `that` on a best-effort
+ * (weak) basis, matching by type, orientation, and name.
+ *
+ * @note unconnected elements will NOT generate errors or warnings
+ *
+ * @example
+ * {{{
+ * // Pass through wires in this module's io to those mySubModule's io,
+ * // matching by type, orientation, and name, and ignoring extra wires.
+ * mySubModule.io <> io
+ * }}}
+ */
+ override def <> (that: Data): Unit = that match {
+ case _: Bundle => this bulkConnect that
+ case _ => this badConnect that
+ }
+
+ // TODO: replace with better defined FIRRTL strong-connect operator
+ override def := (that: Data): Unit = this <> that
+
+ lazy val elements: ListMap[String, Data] = ListMap(namedElts:_*)
+
+ /** Returns a best guess at whether a field in this Bundle is a user-defined
+ * Bundle element without looking at type signatures.
+ */
+ private def isBundleField(m: java.lang.reflect.Method) =
+ m.getParameterTypes.isEmpty &&
+ !java.lang.reflect.Modifier.isStatic(m.getModifiers) &&
+ !(Bundle.keywords contains m.getName) && !(m.getName contains '$')
+
+ /** Returns a field's contained user-defined Bundle element if it appears to
+ * be one, otherwise returns None.
+ */
+ private def getBundleField(m: java.lang.reflect.Method): Option[Data] = {
+ if (isBundleField(m) &&
+ (classOf[Data].isAssignableFrom(m.getReturnType) ||
+ classOf[Option[_]].isAssignableFrom(m.getReturnType))) {
+ m.invoke(this) match {
+ case d: Data =>
+ Some(d)
+ case o: Option[_] =>
+ o.getOrElse(None) match {
+ case d: Data =>
+ Some(d)
+ case _ => None
+ }
+ case _ => None
+ }
+ } else {
+ None
+ }
+ }
+
+ /** Returns a list of elements in this Bundle.
+ */
+ private[Chisel] lazy val namedElts = {
+ val nameMap = LinkedHashMap[String, Data]()
+ val seen = HashSet[Data]()
+ for (m <- getClass.getMethods.sortWith(_.getName < _.getName)) {
+ getBundleField(m) match {
+ case Some(d) =>
+ if (nameMap contains m.getName) {
+ require(nameMap(m.getName) eq d)
+ } else if (!seen(d)) {
+ nameMap(m.getName) = d; seen += d
+ }
+ case None =>
+ }
+ }
+ ArrayBuffer(nameMap.toSeq:_*) sortWith {case ((an, a), (bn, b)) => (a._id > b._id) || ((a eq b) && (an > bn))}
+ }
+ private[Chisel] def toType = {
+ def eltPort(elt: Data): String = {
+ val flipStr = if (elt.isFlip) "flip " else ""
+ s"${flipStr}${elt.getRef.name} : ${elt.toType}"
+ }
+ s"{${namedElts.reverse.map(e => eltPort(e._2)).mkString(", ")}}"
+ }
+ private[Chisel] lazy val flatten = namedElts.flatMap(_._2.flatten)
+ private[Chisel] def addElt(name: String, elt: Data): Unit =
+ namedElts += name -> elt
+ private[Chisel] override def _onModuleClose: Unit = // scalastyle:ignore method.name
+ for ((name, elt) <- namedElts) { elt.setRef(this, _namespace.name(name)) }
+
+ override def cloneType : this.type = {
+ // If the user did not provide a cloneType method, try invoking one of
+ // the following constructors, not all of which necessarily exist:
+ // - A zero-parameter constructor
+ // - A one-paramater constructor, with null as the argument
+ // - A one-parameter constructor for a nested Bundle, with the enclosing
+ // parent Module as the argument
+ val constructor = this.getClass.getConstructors.head
+ try {
+ val args = Seq.fill(constructor.getParameterTypes.size)(null)
+ constructor.newInstance(args:_*).asInstanceOf[this.type]
+ } catch {
+ case e: java.lang.reflect.InvocationTargetException if e.getCause.isInstanceOf[java.lang.NullPointerException] =>
+ try {
+ constructor.newInstance(_parent.get).asInstanceOf[this.type]
+ } catch {
+ case _: java.lang.reflect.InvocationTargetException | _: java.lang.IllegalArgumentException =>
+ Builder.error(s"Parameterized Bundle ${this.getClass} needs cloneType method. You are probably using " +
+ "an anonymous Bundle object that captures external state and hence is un-cloneTypeable")
+ this
+ }
+ case _: java.lang.reflect.InvocationTargetException | _: java.lang.IllegalArgumentException =>
+ Builder.error(s"Parameterized Bundle ${this.getClass} needs cloneType method")
+ this
+ }
+ }
+}
+
+private[Chisel] object Bundle {
+ val keywords = List("flip", "asInput", "asOutput", "cloneType", "toBits")
+}
diff --git a/chiselFrontend/src/main/scala/Chisel/BitPat.scala b/chiselFrontend/src/main/scala/Chisel/BitPat.scala
new file mode 100644
index 00000000..a1bf1985
--- /dev/null
+++ b/chiselFrontend/src/main/scala/Chisel/BitPat.scala
@@ -0,0 +1,80 @@
+// See LICENSE for license details.
+
+package Chisel
+
+object BitPat {
+ /** Parses a bit pattern string into (bits, mask, width).
+ *
+ * @return bits the literal value, with don't cares being 0
+ * @return mask the mask bits, with don't cares being 0 and cares being 1
+ * @return width the number of bits in the literal, including values and
+ * don't cares.
+ */
+ private def parse(x: String): (BigInt, BigInt, Int) = {
+ // Notes:
+ // While Verilog Xs also handle octal and hex cases, there isn't a
+ // compelling argument and no one has asked for it.
+ // If ? parsing is to be exposed, the return API needs further scrutiny
+ // (especially with things like mask polarity).
+ require(x.head == 'b', "BitPats must be in binary and be prefixed with 'b'")
+ var bits = BigInt(0)
+ var mask = BigInt(0)
+ for (d <- x.tail) {
+ if (d != '_') {
+ require("01?".contains(d), "Literal: " + x + " contains illegal character: " + d)
+ mask = (mask << 1) + (if (d == '?') 0 else 1)
+ bits = (bits << 1) + (if (d == '1') 1 else 0)
+ }
+ }
+ (bits, mask, x.length - 1)
+ }
+
+ /** Creates a [[BitPat]] literal from a string.
+ *
+ * @param n the literal value as a string, in binary, prefixed with 'b'
+ * @note legal characters are '0', '1', and '?', as well as '_' as white
+ * space (which are ignored)
+ */
+ def apply(n: String): BitPat = {
+ val (bits, mask, width) = parse(n)
+ new BitPat(bits, mask, width)
+ }
+
+ /** Creates a [[BitPat]] of all don't cares of the specified bitwidth. */
+ def dontCare(width: Int): BitPat = BitPat("b" + ("?" * width))
+
+ @deprecated("Use BitPat.dontCare", "chisel3")
+ def DC(width: Int): BitPat = dontCare(width) // scalastyle:ignore method.name
+
+ /** Allows BitPats to be used where a UInt is expected.
+ *
+ * @note the BitPat must not have don't care bits (will error out otherwise)
+ */
+ implicit def bitPatToUInt(x: BitPat): UInt = {
+ require(x.mask == (BigInt(1) << x.getWidth) - 1)
+ UInt(x.value, x.getWidth)
+ }
+
+ /** Allows UInts to be used where a BitPat is expected, useful for when an
+ * interface is defined with BitPats but not all cases need the partial
+ * matching capability.
+ *
+ * @note the UInt must be a literal
+ */
+ implicit def apply(x: UInt): BitPat = {
+ require(x.isLit)
+ BitPat("b" + x.litValue.toString(2))
+ }
+}
+
+// TODO: Break out of Core? (this doesn't involve FIRRTL generation)
+/** Bit patterns are literals with masks, used to represent values with don't
+ * cares. Equality comparisons will ignore don't care bits (for example,
+ * BitPat(0b10?1) === UInt(0b1001) and UInt(0b1011)).
+ */
+sealed class BitPat(val value: BigInt, val mask: BigInt, width: Int) {
+ def getWidth: Int = width
+ def === (other: UInt): Bool = UInt(value) === (other & UInt(mask))
+ def =/= (other: UInt): Bool = !(this === other)
+ def != (other: UInt): Bool = this =/= other
+}
diff --git a/chiselFrontend/src/main/scala/Chisel/Bits.scala b/chiselFrontend/src/main/scala/Chisel/Bits.scala
new file mode 100644
index 00000000..44d9b660
--- /dev/null
+++ b/chiselFrontend/src/main/scala/Chisel/Bits.scala
@@ -0,0 +1,571 @@
+// See LICENSE for license details.
+
+package Chisel
+
+import internal._
+import internal.Builder.pushOp
+import internal.firrtl._
+import firrtl.PrimOp._
+
+/** Element is a leaf data type: it cannot contain other Data objects. Example
+ * uses are for representing primitive data types, like integers and bits.
+ */
+abstract class Element(dirArg: Direction, val width: Width) extends Data(dirArg)
+
+/** A data type for values represented by a single bitvector. Provides basic
+ * bitwise operations.
+ */
+sealed abstract class Bits(dirArg: Direction, width: Width, override val litArg: Option[LitArg])
+ extends Element(dirArg, width) {
+ // TODO: perhaps make this concrete?
+ // Arguments for: self-checking code (can't do arithmetic on bits)
+ // Arguments against: generates down to a FIRRTL UInt anyways
+
+ private[Chisel] def fromInt(x: BigInt): this.type
+
+ private[Chisel] def flatten: IndexedSeq[Bits] = IndexedSeq(this)
+
+ def cloneType: this.type = cloneTypeWidth(width)
+
+ override def <> (that: Data): Unit = this := that
+
+ def tail(n: Int): UInt = {
+ val w = width match {
+ case KnownWidth(x) =>
+ require(x >= n, s"Can't tail($n) for width $x < $n")
+ Width(x - n)
+ case UnknownWidth() => Width()
+ }
+ binop(UInt(width = w), TailOp, n)
+ }
+
+ def head(n: Int): UInt = {
+ width match {
+ case KnownWidth(x) => require(x >= n, s"Can't head($n) for width $x < $n")
+ case UnknownWidth() =>
+ }
+ binop(UInt(width = n), HeadOp, n)
+ }
+
+ /** Returns the specified bit on this wire as a [[Bool]], statically
+ * addressed.
+ */
+ final def apply(x: BigInt): Bool = {
+ if (x < 0) {
+ Builder.error(s"Negative bit indices are illegal (got $x)")
+ }
+ if (isLit()) {
+ Bool(((litValue() >> x.toInt) & 1) == 1)
+ } else {
+ pushOp(DefPrim(Bool(), BitsExtractOp, this.ref, ILit(x), ILit(x)))
+ }
+ }
+
+ /** Returns the specified bit on this wire as a [[Bool]], statically
+ * addressed.
+ *
+ * @note convenience method allowing direct use of Ints without implicits
+ */
+ final def apply(x: Int): Bool =
+ apply(BigInt(x))
+
+ /** Returns the specified bit on this wire as a [[Bool]], dynamically
+ * addressed.
+ */
+ final def apply(x: UInt): Bool =
+ (this >> x)(0)
+
+ /** Returns a subset of bits on this wire from `hi` to `lo` (inclusive),
+ * statically addressed.
+ *
+ * @example
+ * {{{
+ * myBits = 0x5 = 0b101
+ * myBits(1,0) => 0b01 // extracts the two least significant bits
+ * }}}
+ */
+ final def apply(x: Int, y: Int): UInt = {
+ if (x < y || y < 0) {
+ Builder.error(s"Invalid bit range ($x,$y)")
+ }
+ val w = x - y + 1
+ if (isLit()) {
+ UInt((litValue >> y) & ((BigInt(1) << w) - 1), w)
+ } else {
+ pushOp(DefPrim(UInt(width = w), BitsExtractOp, this.ref, ILit(x), ILit(y)))
+ }
+ }
+
+ // REVIEW TODO: again, is this necessary? Or just have this and use implicits?
+ final def apply(x: BigInt, y: BigInt): UInt = apply(x.toInt, y.toInt)
+
+ private[Chisel] def unop[T <: Data](dest: T, op: PrimOp): T =
+ pushOp(DefPrim(dest, op, this.ref))
+ private[Chisel] def binop[T <: Data](dest: T, op: PrimOp, other: BigInt): T =
+ pushOp(DefPrim(dest, op, this.ref, ILit(other)))
+ private[Chisel] def binop[T <: Data](dest: T, op: PrimOp, other: Bits): T =
+ pushOp(DefPrim(dest, op, this.ref, other.ref))
+ private[Chisel] def compop(op: PrimOp, other: Bits): Bool =
+ pushOp(DefPrim(Bool(), op, this.ref, other.ref))
+ private[Chisel] def redop(op: PrimOp): Bool =
+ pushOp(DefPrim(Bool(), op, this.ref))
+
+ /** Returns this wire zero padded up to the specified width.
+ *
+ * @note for SInts only, this does sign extension
+ */
+ def pad (other: Int): this.type = binop(cloneTypeWidth(this.width max Width(other)), PadOp, other)
+
+ /** Shift left operation */
+ // REVIEW TODO: redundant
+ // REVIEW TODO: should these return this.type or Bits?
+ def << (other: BigInt): Bits
+
+ /** Returns this wire statically left shifted by the specified amount,
+ * inserting zeros into the least significant bits.
+ *
+ * The width of the output is `other` larger than the input.
+ */
+ def << (other: Int): Bits
+
+ /** Returns this wire dynamically left shifted by the specified amount,
+ * inserting zeros into the least significant bits.
+ *
+ * The width of the output is `pow(2, width(other))` larger than the input.
+ */
+ def << (other: UInt): Bits
+
+ /** Shift right operation */
+ // REVIEW TODO: redundant
+ def >> (other: BigInt): Bits
+
+ /** Returns this wire statically right shifted by the specified amount,
+ * inserting zeros into the most significant bits.
+ *
+ * The width of the output is the same as the input.
+ */
+ def >> (other: Int): Bits
+
+ /** Returns this wire dynamically right shifted by the specified amount,
+ * inserting zeros into the most significant bits.
+ *
+ * The width of the output is the same as the input.
+ */
+ def >> (other: UInt): Bits
+
+ /** Returns the contents of this wire as a [[Vec]] of [[Bool]]s.
+ */
+ def toBools: Vec[Bool] = Vec.tabulate(this.getWidth)(i => this(i))
+
+ /** Reinterpret cast to a SInt.
+ *
+ * @note value not guaranteed to be preserved: for example, an UInt of width
+ * 3 and value 7 (0b111) would become a SInt with value -1
+ */
+ def asSInt(): SInt
+
+ /** Reinterpret cast to an UInt.
+ *
+ * @note value not guaranteed to be preserved: for example, a SInt of width
+ * 3 and value -1 (0b111) would become an UInt with value 7
+ */
+ def asUInt(): UInt
+
+ /** Reinterpret cast to Bits. */
+ def asBits(): Bits = asUInt
+
+ @deprecated("Use asSInt, which makes the reinterpret cast more explicit", "chisel3")
+ final def toSInt(): SInt = asSInt
+ @deprecated("Use asUInt, which makes the reinterpret cast more explicit", "chisel3")
+ final def toUInt(): UInt = asUInt
+
+ def toBool(): Bool = width match {
+ case KnownWidth(1) => this(0)
+ case _ => throwException(s"can't covert UInt<$width> to Bool")
+ }
+
+ /** Returns this wire concatenated with `other`, where this wire forms the
+ * most significant part and `other` forms the least significant part.
+ *
+ * The width of the output is sum of the inputs.
+ */
+ def ## (other: Bits): UInt = {
+ val w = this.width + other.width
+ pushOp(DefPrim(UInt(w), ConcatOp, this.ref, other.ref))
+ }
+
+ @deprecated("Use asBits, which makes the reinterpret cast more explicit and actually returns Bits", "chisel3")
+ override def toBits: UInt = asUInt
+
+ override def fromBits(n: Bits): this.type = {
+ val res = Wire(this).asInstanceOf[this.type]
+ res := n
+ res
+ }
+}
+
+/** Provides a set of operations to create UInt types and literals.
+ * Identical in functionality to the UInt companion object.
+ */
+object Bits extends UIntFactory
+
+// REVIEW TODO: Further discussion needed on what Num actually is.
+/** Abstract trait defining operations available on numeric-like wire data
+ * types.
+ */
+abstract trait Num[T <: Data] {
+ // def << (b: T): T
+ // def >> (b: T): T
+ //def unary_-(): T
+
+ // REVIEW TODO: double check ops conventions against FIRRTL
+
+ /** Outputs the sum of `this` and `b`. The resulting width is the max of the
+ * operands plus 1 (should not overflow).
+ */
+ def + (b: T): T
+
+ /** Outputs the product of `this` and `b`. The resulting width is the sum of
+ * the operands.
+ *
+ * @note can generate a single-cycle multiplier, which can result in
+ * significant cycle time and area costs
+ */
+ def * (b: T): T
+
+ /** Outputs the quotient of `this` and `b`.
+ *
+ * TODO: full rules
+ */
+ def / (b: T): T
+
+ def % (b: T): T
+
+ /** Outputs the difference of `this` and `b`. The resulting width is the max
+ * of the operands plus 1 (should not overflow).
+ */
+ def - (b: T): T
+
+ /** Outputs true if `this` < `b`.
+ */
+ def < (b: T): Bool
+
+ /** Outputs true if `this` <= `b`.
+ */
+ def <= (b: T): Bool
+
+ /** Outputs true if `this` > `b`.
+ */
+ def > (b: T): Bool
+
+ /** Outputs true if `this` >= `b`.
+ */
+ def >= (b: T): Bool
+
+ /** Outputs the minimum of `this` and `b`. The resulting width is the max of
+ * the operands.
+ */
+ def min(b: T): T = Mux(this < b, this.asInstanceOf[T], b)
+
+ /** Outputs the maximum of `this` and `b`. The resulting width is the max of
+ * the operands.
+ */
+ def max(b: T): T = Mux(this < b, b, this.asInstanceOf[T])
+}
+
+/** A data type for unsigned integers, represented as a binary bitvector.
+ * Defines arithmetic operations between other integer types.
+ */
+sealed class UInt private[Chisel] (dir: Direction, width: Width, lit: Option[ULit] = None)
+ extends Bits(dir, width, lit) with Num[UInt] {
+ private[Chisel] override def cloneTypeWidth(w: Width): this.type =
+ new UInt(dir, w).asInstanceOf[this.type]
+ private[Chisel] def toType = s"UInt$width"
+
+ override private[Chisel] def fromInt(value: BigInt): this.type = UInt(value).asInstanceOf[this.type]
+
+ override def := (that: Data): Unit = that match {
+ case _: UInt => this connect that
+ case _ => this badConnect that
+ }
+
+ // TODO: refactor to share documentation with Num or add independent scaladoc
+ def unary_- : UInt = UInt(0) - this
+ def unary_-% : UInt = UInt(0) -% this
+ def +& (other: UInt): UInt = binop(UInt((this.width max other.width) + 1), AddOp, other)
+ def + (other: UInt): UInt = this +% other
+ def +% (other: UInt): UInt = (this +& other) tail 1
+ def -& (other: UInt): UInt = binop(UInt((this.width max other.width) + 1), SubOp, other)
+ def - (other: UInt): UInt = this -% other
+ def -% (other: UInt): UInt = (this -& other) tail 1
+ def * (other: UInt): UInt = binop(UInt(this.width + other.width), TimesOp, other)
+ def * (other: SInt): SInt = other * this
+ def / (other: UInt): UInt = binop(UInt(this.width), DivideOp, other)
+ def % (other: UInt): UInt = binop(UInt(this.width), RemOp, other)
+
+ def & (other: UInt): UInt = binop(UInt(this.width max other.width), BitAndOp, other)
+ def | (other: UInt): UInt = binop(UInt(this.width max other.width), BitOrOp, other)
+ def ^ (other: UInt): UInt = binop(UInt(this.width max other.width), BitXorOp, other)
+
+ /** Returns this wire bitwise-inverted. */
+ def unary_~ : UInt = unop(UInt(width = width), BitNotOp)
+
+ // REVIEW TODO: Can this be defined on Bits?
+ def orR: Bool = this != UInt(0)
+ def andR: Bool = ~this === UInt(0)
+ def xorR: Bool = redop(XorReduceOp)
+
+ def < (other: UInt): Bool = compop(LessOp, other)
+ def > (other: UInt): Bool = compop(GreaterOp, other)
+ def <= (other: UInt): Bool = compop(LessEqOp, other)
+ def >= (other: UInt): Bool = compop(GreaterEqOp, other)
+ def != (other: UInt): Bool = compop(NotEqualOp, other)
+ def =/= (other: UInt): Bool = compop(NotEqualOp, other)
+ def === (other: UInt): Bool = compop(EqualOp, other)
+ def unary_! : Bool = this === Bits(0)
+
+ // REVIEW TODO: Can these also not be defined on Bits?
+ def << (other: Int): UInt = binop(UInt(this.width + other), ShiftLeftOp, other)
+ def << (other: BigInt): UInt = this << other.toInt
+ def << (other: UInt): UInt = binop(UInt(this.width.dynamicShiftLeft(other.width)), DynamicShiftLeftOp, other)
+ def >> (other: Int): UInt = binop(UInt(this.width.shiftRight(other)), ShiftRightOp, other)
+ def >> (other: BigInt): UInt = this >> other.toInt
+ def >> (other: UInt): UInt = binop(UInt(this.width), DynamicShiftRightOp, other)
+
+ def bitSet(off: UInt, dat: Bool): UInt = {
+ val bit = UInt(1, 1) << off
+ Mux(dat, this | bit, ~(~this | bit))
+ }
+
+ def === (that: BitPat): Bool = that === this
+ def != (that: BitPat): Bool = that != this
+ def =/= (that: BitPat): Bool = that =/= this
+
+ /** Returns this UInt as a [[SInt]] with an additional zero in the MSB.
+ */
+ // TODO: this eventually will be renamed as toSInt, once the existing toSInt
+ // completes its deprecation phase.
+ def zext(): SInt = pushOp(DefPrim(SInt(width + 1), ConvertOp, ref))
+
+ /** Returns this UInt as a [[SInt]], without changing width or bit value. The
+ * SInt is not guaranteed to have the same value (for example, if the MSB is
+ * high, it will be interpreted as a negative value).
+ */
+ def asSInt(): SInt = pushOp(DefPrim(SInt(width), AsSIntOp, ref))
+
+ def asUInt(): UInt = this
+}
+
+// This is currently a factory because both Bits and UInt inherit it.
+private[Chisel] sealed trait UIntFactory {
+ /** Create a UInt type with inferred width. */
+ def apply(): UInt = apply(NO_DIR, Width())
+ /** Create a UInt type or port with fixed width. */
+ def apply(dir: Direction = NO_DIR, width: Int): UInt = apply(dir, Width(width))
+ /** Create a UInt port with inferred width. */
+ def apply(dir: Direction): UInt = apply(dir, Width())
+
+ /** Create a UInt literal with inferred width. */
+ def apply(value: BigInt): UInt = apply(value, Width())
+ /** Create a UInt literal with fixed width. */
+ def apply(value: BigInt, width: Int): UInt = apply(value, Width(width))
+ /** Create a UInt literal with inferred width. */
+ def apply(n: String): UInt = apply(parse(n), parsedWidth(n))
+ /** Create a UInt literal with fixed width. */
+ def apply(n: String, width: Int): UInt = apply(parse(n), width)
+
+ /** Create a UInt type with specified width. */
+ def apply(width: Width): UInt = apply(NO_DIR, width)
+ /** Create a UInt port with specified width. */
+ def apply(dir: Direction, width: Width): UInt = new UInt(dir, width)
+ /** Create a UInt literal with specified width. */
+ def apply(value: BigInt, width: Width): UInt = {
+ val lit = ULit(value, width)
+ new UInt(NO_DIR, lit.width, Some(lit))
+ }
+
+ private def parse(n: String) = {
+ val (base, num) = n.splitAt(1)
+ val radix = base match {
+ case "x" | "h" => 16
+ case "d" => 10
+ case "o" => 8
+ case "b" => 2
+ case _ => Builder.error(s"Invalid base $base"); 2
+ }
+ BigInt(num.filterNot(_ == '_'), radix)
+ }
+
+ private def parsedWidth(n: String) =
+ if (n(0) == 'b') {
+ Width(n.length-1)
+ } else if (n(0) == 'h') {
+ Width((n.length-1) * 4)
+ } else {
+ Width()
+ }
+}
+
+object UInt extends UIntFactory
+
+sealed class SInt private (dir: Direction, width: Width, lit: Option[SLit] = None)
+ extends Bits(dir, width, lit) with Num[SInt] {
+ private[Chisel] override def cloneTypeWidth(w: Width): this.type =
+ new SInt(dir, w).asInstanceOf[this.type]
+ private[Chisel] def toType = s"SInt$width"
+
+ override def := (that: Data): Unit = that match {
+ case _: SInt => this connect that
+ case _ => this badConnect that
+ }
+
+ override private[Chisel] def fromInt(value: BigInt): this.type = SInt(value).asInstanceOf[this.type]
+
+ def unary_- : SInt = SInt(0) - this
+ def unary_-% : SInt = SInt(0) -% this
+ /** add (width +1) operator */
+ def +& (other: SInt): SInt = binop(SInt((this.width max other.width) + 1), AddOp, other)
+ /** add (default - no growth) operator */
+ def + (other: SInt): SInt = this +% other
+ /** add (no growth) operator */
+ def +% (other: SInt): SInt = (this +& other).tail(1).asSInt
+ /** subtract (width +1) operator */
+ def -& (other: SInt): SInt = binop(SInt((this.width max other.width) + 1), SubOp, other)
+ /** subtract (default - no growth) operator */
+ def - (other: SInt): SInt = this -% other
+ /** subtract (no growth) operator */
+ def -% (other: SInt): SInt = (this -& other).tail(1).asSInt
+ def * (other: SInt): SInt = binop(SInt(this.width + other.width), TimesOp, other)
+ def * (other: UInt): SInt = binop(SInt(this.width + other.width), TimesOp, other)
+ def / (other: SInt): SInt = binop(SInt(this.width), DivideOp, other)
+ def % (other: SInt): SInt = binop(SInt(this.width), RemOp, other)
+
+ def & (other: SInt): SInt = binop(UInt(this.width max other.width), BitAndOp, other).asSInt
+ def | (other: SInt): SInt = binop(UInt(this.width max other.width), BitOrOp, other).asSInt
+ def ^ (other: SInt): SInt = binop(UInt(this.width max other.width), BitXorOp, other).asSInt
+
+ /** Returns this wire bitwise-inverted. */
+ def unary_~ : SInt = unop(UInt(width = width), BitNotOp).asSInt
+
+ def < (other: SInt): Bool = compop(LessOp, other)
+ def > (other: SInt): Bool = compop(GreaterOp, other)
+ def <= (other: SInt): Bool = compop(LessEqOp, other)
+ def >= (other: SInt): Bool = compop(GreaterEqOp, other)
+ def != (other: SInt): Bool = compop(NotEqualOp, other)
+ def =/= (other: SInt): Bool = compop(NotEqualOp, other)
+ def === (other: SInt): Bool = compop(EqualOp, other)
+ def abs(): UInt = Mux(this < SInt(0), (-this).asUInt, this.asUInt)
+
+ def << (other: Int): SInt = binop(SInt(this.width + other), ShiftLeftOp, other)
+ def << (other: BigInt): SInt = this << other.toInt
+ def << (other: UInt): SInt = binop(SInt(this.width.dynamicShiftLeft(other.width)), DynamicShiftLeftOp, other)
+ def >> (other: Int): SInt = binop(SInt(this.width.shiftRight(other)), ShiftRightOp, other)
+ def >> (other: BigInt): SInt = this >> other.toInt
+ def >> (other: UInt): SInt = binop(SInt(this.width), DynamicShiftRightOp, other)
+
+ def asUInt(): UInt = pushOp(DefPrim(UInt(this.width), AsUIntOp, ref))
+ def asSInt(): SInt = this
+}
+
+object SInt {
+ /** Create an SInt type with inferred width. */
+ def apply(): SInt = apply(NO_DIR, Width())
+ /** Create an SInt type or port with fixed width. */
+ def apply(dir: Direction = NO_DIR, width: Int): SInt = apply(dir, Width(width))
+ /** Create an SInt port with inferred width. */
+ def apply(dir: Direction): SInt = apply(dir, Width())
+
+ /** Create an SInt literal with inferred width. */
+ def apply(value: BigInt): SInt = apply(value, Width())
+ /** Create an SInt literal with fixed width. */
+ def apply(value: BigInt, width: Int): SInt = apply(value, Width(width))
+
+ /** Create an SInt type with specified width. */
+ def apply(width: Width): SInt = new SInt(NO_DIR, width)
+ /** Create an SInt port with specified width. */
+ def apply(dir: Direction, width: Width): SInt = new SInt(dir, width)
+ /** Create an SInt literal with specified width. */
+ def apply(value: BigInt, width: Width): SInt = {
+ val lit = SLit(value, width)
+ new SInt(NO_DIR, lit.width, Some(lit))
+ }
+}
+
+// REVIEW TODO: Why does this extend UInt and not Bits? Does defining airth
+// operations on a Bool make sense?
+/** A data type for booleans, defined as a single bit indicating true or false.
+ */
+sealed class Bool(dir: Direction, lit: Option[ULit] = None) extends UInt(dir, Width(1), lit) {
+ private[Chisel] override def cloneTypeWidth(w: Width): this.type = {
+ require(!w.known || w.get == 1)
+ new Bool(dir).asInstanceOf[this.type]
+ }
+
+ override private[Chisel] def fromInt(value: BigInt): this.type = {
+ require(value == 0 || value == 1)
+ Bool(value == 1).asInstanceOf[this.type]
+ }
+
+ // REVIEW TODO: Why does this need to exist and have different conventions
+ // than Bits?
+ def & (other: Bool): Bool = binop(Bool(), BitAndOp, other)
+ def | (other: Bool): Bool = binop(Bool(), BitOrOp, other)
+ def ^ (other: Bool): Bool = binop(Bool(), BitXorOp, other)
+
+ /** Returns this wire bitwise-inverted. */
+ override def unary_~ : Bool = unop(Bool(), BitNotOp)
+
+ /** Outputs the logical OR of two Bools.
+ */
+ def || (that: Bool): Bool = this | that
+
+ /** Outputs the logical AND of two Bools.
+ */
+ def && (that: Bool): Bool = this & that
+}
+
+object Bool {
+ /** Creates an empty Bool.
+ */
+ def apply(dir: Direction = NO_DIR): Bool = new Bool(dir)
+
+ /** Creates Bool literal.
+ */
+ def apply(x: Boolean): Bool = new Bool(NO_DIR, Some(ULit(if (x) 1 else 0, Width(1))))
+}
+
+object Mux {
+ /** Creates a mux, whose output is one of the inputs depending on the
+ * value of the condition.
+ *
+ * @param cond condition determining the input to choose
+ * @param con the value chosen when `cond` is true
+ * @param alt the value chosen when `cond` is false
+ * @example
+ * {{{
+ * val muxOut = Mux(data_in === UInt(3), UInt(3, 4), UInt(0, 4))
+ * }}}
+ */
+ def apply[T <: Data](cond: Bool, con: T, alt: T): T = (con, alt) match {
+ // Handle Mux(cond, UInt, Bool) carefully so that the concrete type is UInt
+ case (c: Bool, a: Bool) => doMux(cond, c, a).asInstanceOf[T]
+ case (c: UInt, a: Bool) => doMux(cond, c, a << 0).asInstanceOf[T]
+ case (c: Bool, a: UInt) => doMux(cond, c << 0, a).asInstanceOf[T]
+ case (c: Bits, a: Bits) => doMux(cond, c, a).asInstanceOf[T]
+ case _ => doAggregateMux(cond, con, alt)
+ }
+
+ private def doMux[T <: Data](cond: Bool, con: T, alt: T): T = {
+ require(con.getClass == alt.getClass, s"can't Mux between ${con.getClass} and ${alt.getClass}")
+ val d = alt.cloneTypeWidth(con.width max alt.width)
+ pushOp(DefPrim(d, MultiplexOp, cond.ref, con.ref, alt.ref))
+ }
+
+ private def doAggregateMux[T <: Data](cond: Bool, con: T, alt: T): T = {
+ require(con.getClass == alt.getClass, s"can't Mux between ${con.getClass} and ${alt.getClass}")
+ for ((c, a) <- con.flatten zip alt.flatten)
+ require(c.width == a.width, "can't Mux between aggregates of different width")
+ doMux(cond, con, alt)
+ }
+}
+
diff --git a/chiselFrontend/src/main/scala/Chisel/BlackBox.scala b/chiselFrontend/src/main/scala/Chisel/BlackBox.scala
new file mode 100644
index 00000000..be72934d
--- /dev/null
+++ b/chiselFrontend/src/main/scala/Chisel/BlackBox.scala
@@ -0,0 +1,54 @@
+// See LICENSE for license details.
+
+package Chisel
+
+import internal.Builder.pushCommand
+import internal.firrtl.{ModuleIO, DefInvalid}
+
+/** Defines a black box, which is a module that can be referenced from within
+ * Chisel, but is not defined in the emitted Verilog. Useful for connecting
+ * to RTL modules defined outside Chisel.
+ *
+ * @example
+ * {{{
+ * ... to be written once a spec is finalized ...
+ * }}}
+ */
+// REVIEW TODO: make Verilog parameters part of the constructor interface?
+abstract class BlackBox extends Module {
+ // Don't bother taking override_clock|reset, clock/reset locked out anyway
+ // TODO: actually implement this.
+ def setVerilogParameters(s: String): Unit = {}
+
+ // The body of a BlackBox is empty, the real logic happens in firrtl/Emitter.scala
+ // Bypass standard clock, reset, io port declaration by flattening io
+ // TODO(twigg): ? Really, overrides are bad, should extend BaseModule....
+ override private[Chisel] def ports = io.elements.toSeq
+
+ // Do not do reflective naming of internal signals, just name io
+ override private[Chisel] def setRefs(): this.type = {
+ for ((name, port) <- ports) {
+ port.setRef(ModuleIO(this, _namespace.name(name)))
+ }
+ // setRef is not called on the actual io.
+ // There is a risk of user improperly attempting to connect directly with io
+ // Long term solution will be to define BlackBox IO differently as part of
+ // it not descending from the (current) Module
+ this
+ }
+
+ // Don't setup clock, reset
+ // Cann't invalide io in one bunch, must invalidate each part separately
+ override private[Chisel] def setupInParent(): this.type = _parent match {
+ case Some(p) => {
+ // Just init instance inputs
+ for((_,port) <- ports) pushCommand(DefInvalid(port.ref))
+ this
+ }
+ case None => this
+ }
+
+ // Using null is horrible but these signals SHOULD NEVER be used:
+ override val clock = null
+ override val reset = null
+}
diff --git a/chiselFrontend/src/main/scala/Chisel/CoreUtil.scala b/chiselFrontend/src/main/scala/Chisel/CoreUtil.scala
new file mode 100644
index 00000000..708b516e
--- /dev/null
+++ b/chiselFrontend/src/main/scala/Chisel/CoreUtil.scala
@@ -0,0 +1,97 @@
+// See LICENSE for license details.
+
+package Chisel
+
+import internal._
+import internal.Builder.pushCommand
+import internal.firrtl._
+
+import scala.language.experimental.macros
+import scala.reflect.macros.blackbox.Context
+
+object assert { // scalastyle:ignore object.name
+ /** Checks for a condition to be valid in the circuit at all times. If the
+ * condition evaluates to false, the circuit simulation stops with an error.
+ *
+ * Does not fire when in reset (defined as the encapsulating Module's
+ * reset). If your definition of reset is not the encapsulating Module's
+ * reset, you will need to gate this externally.
+ *
+ * May be called outside of a Module (like defined in a function), so
+ * functions using assert make the standard Module assumptions (single clock
+ * and single reset).
+ *
+ * @param cond condition, assertion fires (simulation fails) when false
+ * @param message optional message to print when the assertion fires
+ *
+ * @note currently cannot be used in core Chisel / libraries because macro
+ * defs need to be compiled first and the SBT project is not set up to do
+ * that
+ */
+ def apply(cond: Bool, message: String): Unit = macro apply_impl_msg
+ def apply(cond: Bool): Unit = macro apply_impl // macros currently can't take default arguments
+
+ def apply_impl_msg(c: Context)(cond: c.Tree, message: c.Tree): c.Tree = {
+ import c.universe._
+ val p = c.enclosingPosition
+ val condStr = s"${p.source.file.name}:${p.line} ${p.lineContent.trim}"
+ val apply_impl_do = symbolOf[this.type].asClass.module.info.member(TermName("apply_impl_do"))
+ q"$apply_impl_do($cond, $condStr, _root_.scala.Some($message))"
+ }
+
+ def apply_impl(c: Context)(cond: c.Tree): c.Tree = {
+ import c.universe._
+ val p = c.enclosingPosition
+ val condStr = s"${p.source.file.name}:${p.line} ${p.lineContent.trim}"
+ val apply_impl_do = symbolOf[this.type].asClass.module.info.member(TermName("apply_impl_do"))
+ q"$apply_impl_do($cond, $condStr, _root_.scala.None)"
+ }
+
+ def apply_impl_do(cond: Bool, line: String, message: Option[String]) {
+ when (!(cond || Builder.dynamicContext.currentModule.get.reset)) {
+ message match {
+ case Some(str) => printf.printfWithoutReset(s"Assertion failed: $str\n at $line\n")
+ case None => printf.printfWithoutReset(s"Assertion failed\n at $line\n")
+ }
+ pushCommand(Stop(Node(Builder.dynamicContext.currentModule.get.clock), 1))
+ }
+ }
+
+ /** An elaboration-time assertion, otherwise the same as the above run-time
+ * assertion. */
+ def apply(cond: Boolean, message: => String) {
+ Predef.assert(cond, message)
+ }
+
+ /** A workaround for default-value overloading problems in Scala, just
+ * 'assert(cond, "")' */
+ def apply(cond: Boolean) {
+ Predef.assert(cond, "")
+ }
+}
+
+object printf { // scalastyle:ignore object.name
+ /** Prints a message in simulation.
+ *
+ * Does not fire when in reset (defined as the encapsulating Module's
+ * reset). If your definition of reset is not the encapsulating Module's
+ * reset, you will need to gate this externally.
+ *
+ * May be called outside of a Module (like defined in a function), so
+ * functions using printf make the standard Module assumptions (single clock
+ * and single reset).
+ *
+ * @param fmt printf format string
+ * @param data format string varargs containing data to print
+ */
+ def apply(fmt: String, data: Bits*) {
+ when (!Builder.dynamicContext.currentModule.get.reset) {
+ printfWithoutReset(fmt, data:_*)
+ }
+ }
+
+ private[Chisel] def printfWithoutReset(fmt: String, data: Bits*) {
+ val clock = Builder.dynamicContext.currentModule.get.clock
+ pushCommand(Printf(Node(clock), fmt, data.map((d: Bits) => d.ref)))
+ }
+}
diff --git a/chiselFrontend/src/main/scala/Chisel/Data.scala b/chiselFrontend/src/main/scala/Chisel/Data.scala
new file mode 100644
index 00000000..8879491c
--- /dev/null
+++ b/chiselFrontend/src/main/scala/Chisel/Data.scala
@@ -0,0 +1,152 @@
+// See LICENSE for license details.
+
+package Chisel
+
+import internal._
+import internal.Builder.pushCommand
+import internal.firrtl._
+
+sealed abstract class Direction(name: String) {
+ override def toString: String = name
+ def flip: Direction
+}
+object INPUT extends Direction("input") { override def flip: Direction = OUTPUT }
+object OUTPUT extends Direction("output") { override def flip: Direction = INPUT }
+object NO_DIR extends Direction("?") { override def flip: Direction = NO_DIR }
+
+@deprecated("debug doesn't do anything in Chisel3 as no pruning happens in the frontend", "chisel3")
+object debug { // scalastyle:ignore object.name
+ def apply (arg: Data): Data = arg
+}
+
+/** Mixing in this trait flips the direction of an Aggregate. */
+trait Flipped extends Data {
+ this.overrideDirection(_.flip, !_)
+}
+
+/** This forms the root of the type system for wire data types. The data value
+ * must be representable as some number (need not be known at Chisel compile
+ * time) of bits, and must have methods to pack / unpack structured data to /
+ * from bits.
+ */
+abstract class Data(dirArg: Direction) extends HasId {
+ def dir: Direction = dirVar
+
+ // Sucks this is mutable state, but cloneType doesn't take a Direction arg
+ private var isFlipVar = dirArg == INPUT
+ private var dirVar = dirArg
+ private[Chisel] def isFlip = isFlipVar
+
+ private[Chisel] def overrideDirection(newDir: Direction => Direction,
+ newFlip: Boolean => Boolean): this.type = {
+ this.isFlipVar = newFlip(this.isFlipVar)
+ for (field <- this.flatten)
+ (field: Data).dirVar = newDir((field: Data).dirVar)
+ this
+ }
+ def asInput: this.type = cloneType.overrideDirection(_ => INPUT, _ => true)
+ def asOutput: this.type = cloneType.overrideDirection(_ => OUTPUT, _ => false)
+ def flip(): this.type = cloneType.overrideDirection(_.flip, !_)
+
+ private[Chisel] def badConnect(that: Data): Unit =
+ throwException(s"cannot connect ${this} and ${that}")
+ private[Chisel] def connect(that: Data): Unit =
+ pushCommand(Connect(this.lref, that.ref))
+ private[Chisel] def bulkConnect(that: Data): Unit =
+ pushCommand(BulkConnect(this.lref, that.lref))
+ private[Chisel] def lref: Node = Node(this)
+ private[Chisel] def ref: Arg = if (isLit) litArg.get else lref
+ private[Chisel] def cloneTypeWidth(width: Width): this.type
+ private[Chisel] def toType: String
+
+ def := (that: Data): Unit = this badConnect that
+ def <> (that: Data): Unit = this badConnect that
+ def cloneType: this.type
+ def litArg(): Option[LitArg] = None
+ def litValue(): BigInt = litArg.get.num
+ def isLit(): Boolean = litArg.isDefined
+
+ def width: Width
+ final def getWidth: Int = width.get
+
+ // While this being in the Data API doesn't really make sense (should be in
+ // Aggregate, right?) this is because of an implementation limitation:
+ // cloneWithDirection, which is private and defined here, needs flatten to
+ // set element directionality.
+ // Related: directionality is mutable state. A possible solution for both is
+ // to define directionality relative to the container, but these parent links
+ // currently don't exist (while this information may be available during
+ // FIRRTL emission, it would break directionality querying from Chisel, which
+ // does get used).
+ private[Chisel] def flatten: IndexedSeq[Bits]
+
+ /** Creates an new instance of this type, unpacking the input Bits into
+ * structured data.
+ *
+ * This performs the inverse operation of toBits.
+ *
+ * @note does NOT assign to the object this is called on, instead creates
+ * and returns a NEW object (useful in a clone-and-assign scenario)
+ * @note does NOT check bit widths, may drop bits during assignment
+ * @note what fromBits assigs to must have known widths
+ */
+ def fromBits(n: Bits): this.type = {
+ var i = 0
+ val wire = Wire(this.cloneType)
+ val bits =
+ if (n.width.known && n.width.get >= wire.width.get) {
+ n
+ } else {
+ Wire(n.cloneTypeWidth(wire.width), init = n)
+ }
+ for (x <- wire.flatten) {
+ x := bits(i + x.getWidth-1, i)
+ i += x.getWidth
+ }
+ wire.asInstanceOf[this.type]
+ }
+
+ /** Packs the value of this object as plain Bits.
+ *
+ * This performs the inverse operation of fromBits(Bits).
+ */
+ def toBits(): UInt = SeqUtils.asUInt(this.flatten)
+}
+
+object Wire {
+ def apply[T <: Data](t: T): T =
+ makeWire(t, null.asInstanceOf[T])
+
+ def apply[T <: Data](dummy: Int = 0, init: T): T =
+ makeWire(null.asInstanceOf[T], init)
+
+ def apply[T <: Data](t: T, init: T): T =
+ makeWire(t, init)
+
+ private def makeWire[T <: Data](t: T, init: T): T = {
+ val x = Reg.makeType(t, null.asInstanceOf[T], init)
+ pushCommand(DefWire(x))
+ pushCommand(DefInvalid(x.ref))
+ if (init != null) {
+ x := init
+ }
+ x
+ }
+}
+
+object Clock {
+ def apply(dir: Direction = NO_DIR): Clock = new Clock(dir)
+}
+
+// TODO: Document this.
+sealed class Clock(dirArg: Direction) extends Element(dirArg, Width(1)) {
+ def cloneType: this.type = Clock(dirArg).asInstanceOf[this.type]
+ private[Chisel] override def flatten: IndexedSeq[Bits] = IndexedSeq()
+ private[Chisel] def cloneTypeWidth(width: Width): this.type = cloneType
+ private[Chisel] def toType = "Clock"
+
+ override def := (that: Data): Unit = that match {
+ case _: Clock => this connect that
+ case _ => this badConnect that
+ }
+}
diff --git a/chiselFrontend/src/main/scala/Chisel/Mem.scala b/chiselFrontend/src/main/scala/Chisel/Mem.scala
new file mode 100644
index 00000000..17ac9ca5
--- /dev/null
+++ b/chiselFrontend/src/main/scala/Chisel/Mem.scala
@@ -0,0 +1,123 @@
+// See LICENSE for license details.
+
+package Chisel
+
+import internal._
+import internal.Builder.pushCommand
+import internal.firrtl._
+
+object Mem {
+ @deprecated("Mem argument order should be size, t; this will be removed by the official release", "chisel3")
+ def apply[T <: Data](t: T, size: Int): Mem[T] = apply(size, t)
+
+ /** Creates a combinational-read, sequential-write [[Mem]].
+ *
+ * @param size number of elements in the memory
+ * @param t data type of memory element
+ */
+ def apply[T <: Data](size: Int, t: T): Mem[T] = {
+ val mt = t.cloneType
+ val mem = new Mem(mt, size)
+ pushCommand(DefMemory(mem, mt, size)) // TODO multi-clock
+ mem
+ }
+}
+
+sealed abstract class MemBase[T <: Data](t: T, val length: Int) extends HasId with VecLike[T] {
+ // REVIEW TODO: make accessors (static/dynamic, read/write) combinations consistent.
+
+ /** Creates a read accessor into the memory with static addressing. See the
+ * class documentation of the memory for more detailed information.
+ */
+ def apply(idx: Int): T = apply(UInt(idx))
+
+ /** Creates a read/write accessor into the memory with dynamic addressing.
+ * See the class documentation of the memory for more detailed information.
+ */
+ def apply(idx: UInt): T = makePort(idx, MemPortDirection.INFER)
+
+ /** Creates a read accessor into the memory with dynamic addressing. See the
+ * class documentation of the memory for more detailed information.
+ */
+ def read(idx: UInt): T = makePort(idx, MemPortDirection.READ)
+
+ /** Creates a write accessor into the memory.
+ *
+ * @param idx memory element index to write into
+ * @param data new data to write
+ */
+ def write(idx: UInt, data: T): Unit = {
+ makePort(idx, MemPortDirection.WRITE) := data
+ }
+
+ /** Creates a masked write accessor into the memory.
+ *
+ * @param idx memory element index to write into
+ * @param data new data to write
+ * @param mask write mask as a Vec of Bool: a write to the Vec element in
+ * memory is only performed if the corresponding mask index is true.
+ *
+ * @note this is only allowed if the memory's element data type is a Vec
+ */
+ def write(idx: UInt, data: T, mask: Vec[Bool]) (implicit evidence: T <:< Vec[_]): Unit = {
+ val accessor = makePort(idx, MemPortDirection.WRITE).asInstanceOf[Vec[Data]]
+ val dataVec = data.asInstanceOf[Vec[Data]]
+ if (accessor.length != dataVec.length) {
+ Builder.error(s"Mem write data must contain ${accessor.length} elements (found ${dataVec.length})")
+ }
+ if (accessor.length != mask.length) {
+ Builder.error(s"Mem write mask must contain ${accessor.length} elements (found ${mask.length})")
+ }
+ for (((cond, port), datum) <- mask zip accessor zip dataVec)
+ when (cond) { port := datum }
+ }
+
+ private def makePort(idx: UInt, dir: MemPortDirection): T =
+ pushCommand(DefMemPort(t.cloneType, Node(this), dir, idx.ref, Node(idx._parent.get.clock))).id
+}
+
+/** A combinational-read, sequential-write memory.
+ *
+ * Writes take effect on the rising clock edge after the request. Reads are
+ * combinational (requests will return data on the same cycle).
+ * Read-after-write hazards are not an issue.
+ *
+ * @note when multiple conflicting writes are performed on a Mem element, the
+ * result is undefined (unlike Vec, where the last assignment wins)
+ */
+sealed class Mem[T <: Data](t: T, length: Int) extends MemBase(t, length)
+
+object SeqMem {
+ @deprecated("SeqMem argument order should be size, t; this will be removed by the official release", "chisel3")
+ def apply[T <: Data](t: T, size: Int): SeqMem[T] = apply(size, t)
+
+ /** Creates a sequential-read, sequential-write [[SeqMem]].
+ *
+ * @param size number of elements in the memory
+ * @param t data type of memory element
+ */
+ def apply[T <: Data](size: Int, t: T): SeqMem[T] = {
+ val mt = t.cloneType
+ val mem = new SeqMem(mt, size)
+ pushCommand(DefSeqMemory(mem, mt, size)) // TODO multi-clock
+ mem
+ }
+}
+
+/** A sequential-read, sequential-write memory.
+ *
+ * Writes take effect on the rising clock edge after the request. Reads return
+ * data on the rising edge after the request. Read-after-write behavior (when
+ * a read and write to the same address are requested on the same cycle) is
+ * undefined.
+ *
+ * @note when multiple conflicting writes are performed on a Mem element, the
+ * result is undefined (unlike Vec, where the last assignment wins)
+ */
+sealed class SeqMem[T <: Data](t: T, n: Int) extends MemBase[T](t, n) {
+ def read(addr: UInt, enable: Bool): T = {
+ val a = Wire(UInt())
+ when (enable) { a := addr }
+ read(a)
+ }
+}
diff --git a/chiselFrontend/src/main/scala/Chisel/Module.scala b/chiselFrontend/src/main/scala/Chisel/Module.scala
new file mode 100644
index 00000000..3e839cac
--- /dev/null
+++ b/chiselFrontend/src/main/scala/Chisel/Module.scala
@@ -0,0 +1,103 @@
+// See LICENSE for license details.
+
+package Chisel
+
+import scala.collection.mutable.{ArrayBuffer, HashSet}
+
+import internal._
+import internal.Builder.pushCommand
+import internal.Builder.dynamicContext
+import internal.firrtl._
+
+object Module {
+ /** A wrapper method that all Module instantiations must be wrapped in
+ * (necessary to help Chisel track internal state).
+ *
+ * @param m the Module being created
+ *
+ * @return the input module `m` with Chisel metadata properly set
+ */
+ def apply[T <: Module](bc: => T): T = {
+ val parent = dynamicContext.currentModule
+ val m = bc.setRefs()
+ m._commands.prepend(DefInvalid(m.io.ref)) // init module outputs
+ dynamicContext.currentModule = parent
+ val ports = m.computePorts
+ Builder.components += Component(m, m.name, ports, m._commands)
+ pushCommand(DefInstance(m, ports))
+ m.setupInParent()
+ }
+}
+
+/** Abstract base class for Modules, which behave much like Verilog modules.
+ * These may contain both logic and state which are written in the Module
+ * body (constructor).
+ *
+ * @note Module instantiations must be wrapped in a Module() call.
+ */
+abstract class Module(
+ override_clock: Option[Clock]=None, override_reset: Option[Bool]=None)
+extends HasId {
+ // _clock and _reset can be clock and reset in these 2ary constructors
+ // once chisel2 compatibility issues are resolved
+ def this(_clock: Clock) = this(Some(_clock), None)
+ def this(_reset: Bool) = this(None, Some(_reset))
+ def this(_clock: Clock, _reset: Bool) = this(Some(_clock), Some(_reset))
+
+ private[Chisel] val _namespace = Builder.globalNamespace.child
+ private[Chisel] val _commands = ArrayBuffer[Command]()
+ private[Chisel] val _ids = ArrayBuffer[HasId]()
+ dynamicContext.currentModule = Some(this)
+
+ /** Name of the instance. */
+ val name = Builder.globalNamespace.name(getClass.getName.split('.').last)
+
+ /** IO for this Module. At the Scala level (pre-FIRRTL transformations),
+ * connections in and out of a Module may only go through `io` elements.
+ */
+ def io: Bundle
+ val clock = Clock(INPUT)
+ val reset = Bool(INPUT)
+
+ private[Chisel] def addId(d: HasId) { _ids += d }
+
+ private[Chisel] def ports: Seq[(String,Data)] = Vector(
+ ("clk", clock), ("reset", reset), ("io", io)
+ )
+
+ private[Chisel] def computePorts = for((name, port) <- ports) yield {
+ val bundleDir = if (port.isFlip) INPUT else OUTPUT
+ Port(port, if (port.dir == NO_DIR) bundleDir else port.dir)
+ }
+
+ private[Chisel] def setupInParent(): this.type = _parent match {
+ case Some(p) => {
+ pushCommand(DefInvalid(io.ref)) // init instance inputs
+ clock := override_clock.getOrElse(p.clock)
+ reset := override_reset.getOrElse(p.reset)
+ this
+ }
+ case None => this
+ }
+
+ private[Chisel] def setRefs(): this.type = {
+ for ((name, port) <- ports) {
+ port.setRef(ModuleIO(this, _namespace.name(name)))
+ }
+
+ // Suggest names to nodes using runtime reflection
+ val valNames = HashSet[String](getClass.getDeclaredFields.map(_.getName):_*)
+ def isPublicVal(m: java.lang.reflect.Method) =
+ m.getParameterTypes.isEmpty && valNames.contains(m.getName)
+ val methods = getClass.getMethods.sortWith(_.getName > _.getName)
+ for (m <- methods; if isPublicVal(m)) m.invoke(this) match {
+ case (id: HasId) => id.suggestName(m.getName)
+ case _ =>
+ }
+
+ // All suggestions are in, force names to every node.
+ _ids.foreach(_.forceName(default="T", _namespace))
+ _ids.foreach(_._onModuleClose)
+ this
+ }
+}
diff --git a/chiselFrontend/src/main/scala/Chisel/Reg.scala b/chiselFrontend/src/main/scala/Chisel/Reg.scala
new file mode 100644
index 00000000..e69061c5
--- /dev/null
+++ b/chiselFrontend/src/main/scala/Chisel/Reg.scala
@@ -0,0 +1,66 @@
+// See LICENSE for license details.
+
+package Chisel
+
+import internal._
+import internal.Builder.pushCommand
+import internal.firrtl._
+
+object Reg {
+ private[Chisel] def makeType[T <: Data](t: T = null, next: T = null, init: T = null): T = {
+ if (t ne null) {
+ t.cloneType
+ } else if (next ne null) {
+ next.cloneTypeWidth(Width())
+ } else if (init ne null) {
+ init.litArg match {
+ // For e.g. Reg(init=UInt(0, k)), fix the Reg's width to k
+ case Some(lit) if lit.forcedWidth => init.cloneType
+ case _ => init.cloneTypeWidth(Width())
+ }
+ } else {
+ throwException("cannot infer type")
+ }
+ }
+
+ /** Creates a register with optional next and initialization values.
+ *
+ * @param t: data type for the register
+ * @param next: new value register is to be updated with every cycle (or
+ * empty to not update unless assigned to using the := operator)
+ * @param init: initialization value on reset (or empty for uninitialized,
+ * where the register value persists across a reset)
+ *
+ * @note this may result in a type error if called from a type parameterized
+ * function, since the Scala compiler isn't smart enough to know that null
+ * is a valid value. In those cases, you can either use the outType only Reg
+ * constructor or pass in `null.asInstanceOf[T]`.
+ */
+ def apply[T <: Data](t: T = null, next: T = null, init: T = null): T = {
+ // TODO: write this in a way that doesn't need nulls (bad Scala style),
+ // null.asInstanceOf[T], and two constructors. Using Option types are an
+ // option, but introduces cumbersome syntax (wrap everything in a Some()).
+ // Implicit conversions to Option (or similar) types were also considered,
+ // but Scala's type inferencer and implicit insertion isn't smart enough
+ // to resolve all use cases. If the type inferencer / implicit resolution
+ // system improves, this may be changed.
+ val x = makeType(t, next, init)
+ val clock = Node(x._parent.get.clock) // TODO multi-clock
+ if (init == null) {
+ pushCommand(DefReg(x, clock))
+ } else {
+ pushCommand(DefRegInit(x, clock, Node(x._parent.get.reset), init.ref))
+ }
+ if (next != null) {
+ x := next
+ }
+ x
+ }
+
+ /** Creates a register without initialization (reset is ignored). Value does
+ * not change unless assigned to (using the := operator).
+ *
+ * @param outType: data type for the register
+ */
+ def apply[T <: Data](outType: T): T = Reg[T](outType, null.asInstanceOf[T], null.asInstanceOf[T])
+}
diff --git a/chiselFrontend/src/main/scala/Chisel/SeqUtils.scala b/chiselFrontend/src/main/scala/Chisel/SeqUtils.scala
new file mode 100644
index 00000000..c63f5735
--- /dev/null
+++ b/chiselFrontend/src/main/scala/Chisel/SeqUtils.scala
@@ -0,0 +1,47 @@
+// See LICENSE for license details.
+
+package Chisel
+
+private[Chisel] object SeqUtils {
+ /** Equivalent to Cat(r(n-1), ..., r(0)) */
+ def asUInt[T <: Bits](in: Seq[T]): UInt = {
+ if (in.tail.isEmpty) {
+ in.head.asUInt
+ } else {
+ val left = asUInt(in.slice(0, in.length/2))
+ val right = asUInt(in.slice(in.length/2, in.length))
+ right ## left
+ }
+ }
+
+ /** Counts the number of true Bools in a Seq */
+ def count(in: Seq[Bool]): UInt = {
+ if (in.size == 0) {
+ UInt(0)
+ } else if (in.size == 1) {
+ in.head
+ } else {
+ count(in.slice(0, in.size/2)) + (UInt(0) ## count(in.slice(in.size/2, in.size)))
+ }
+ }
+
+ /** Returns data value corresponding to first true predicate */
+ def priorityMux[T <: Bits](in: Seq[(Bool, T)]): T = {
+ if (in.size == 1) {
+ in.head._2
+ } else {
+ Mux(in.head._1, in.head._2, priorityMux(in.tail))
+ }
+ }
+
+ /** Returns data value corresponding to lone true predicate */
+ def oneHotMux[T <: Data](in: Iterable[(Bool, T)]): T = {
+ if (in.tail.isEmpty) {
+ in.head._2
+ } else {
+ val masked = for ((s, i) <- in) yield Mux(s, i.toBits, Bits(0))
+ val width = in.map(_._2.width).reduce(_ max _)
+ in.head._2.cloneTypeWidth(width).fromBits(masked.reduceLeft(_|_))
+ }
+ }
+}
diff --git a/chiselFrontend/src/main/scala/Chisel/When.scala b/chiselFrontend/src/main/scala/Chisel/When.scala
new file mode 100644
index 00000000..5f6b02c5
--- /dev/null
+++ b/chiselFrontend/src/main/scala/Chisel/When.scala
@@ -0,0 +1,56 @@
+// See LICENSE for license details.
+
+package Chisel
+
+import internal._
+import internal.Builder.pushCommand
+import internal.firrtl._
+
+object when { // scalastyle:ignore object.name
+ /** Create a `when` condition block, where whether a block of logic is
+ * executed or not depends on the conditional.
+ *
+ * @param cond condition to execute upon
+ * @param block logic that runs only if `cond` is true
+ *
+ * @example
+ * {{{
+ * when ( myData === UInt(3) ) {
+ * // Some logic to run when myData equals 3.
+ * } .elsewhen ( myData === UInt(1) ) {
+ * // Some logic to run when myData equals 1.
+ * } .otherwise {
+ * // Some logic to run when myData is neither 3 nor 1.
+ * }
+ * }}}
+ */
+ def apply(cond: Bool)(block: => Unit): WhenContext = {
+ new WhenContext(cond, !cond)(block)
+ }
+}
+
+/** Internal mechanism for generating a when. Because of the way FIRRTL
+ * commands are emitted, generating a FIRRTL elsewhen or nested whens inside
+ * elses would be difficult. Instead, this keeps track of the negative of the
+ * previous conditions, so when an elsewhen or otherwise is used, it checks
+ * that both the condition is true and all the previous conditions have been
+ * false.
+ */
+class WhenContext(cond: Bool, prevCond: => Bool)(block: => Unit) {
+ /** This block of logic gets executed if above conditions have been false
+ * and this condition is true.
+ */
+ def elsewhen (elseCond: Bool)(block: => Unit): WhenContext = {
+ new WhenContext(prevCond && elseCond, prevCond && !elseCond)(block)
+ }
+
+ /** This block of logic gets executed only if the above conditions were all
+ * false. No additional logic blocks may be appended past the `otherwise`.
+ */
+ def otherwise(block: => Unit): Unit =
+ new WhenContext(prevCond, null)(block)
+
+ pushCommand(WhenBegin(cond.ref))
+ block
+ pushCommand(WhenEnd())
+}
diff --git a/chiselFrontend/src/main/scala/Chisel/internal/Builder.scala b/chiselFrontend/src/main/scala/Chisel/internal/Builder.scala
new file mode 100644
index 00000000..c7ecdaa0
--- /dev/null
+++ b/chiselFrontend/src/main/scala/Chisel/internal/Builder.scala
@@ -0,0 +1,122 @@
+// See LICENSE for license details.
+
+package Chisel.internal
+
+import scala.util.DynamicVariable
+import scala.collection.mutable.{ArrayBuffer, HashMap}
+
+import Chisel._
+import Chisel.internal.firrtl._
+
+private[Chisel] class Namespace(parent: Option[Namespace], keywords: Set[String]) {
+ private var i = 0L
+ private val names = collection.mutable.HashSet[String]()
+
+ private def rename(n: String) = { i += 1; s"${n}_${i}" }
+
+ def contains(elem: String): Boolean = {
+ keywords.contains(elem) || names.contains(elem) ||
+ parent.map(_ contains elem).getOrElse(false)
+ }
+
+ def name(elem: String): String = {
+ if (this contains elem) {
+ name(rename(elem))
+ } else {
+ names += elem
+ elem
+ }
+ }
+
+ def child(kws: Set[String]): Namespace = new Namespace(Some(this), kws)
+ def child: Namespace = child(Set())
+}
+
+private[Chisel] class IdGen {
+ private var counter = -1L
+ def next: Long = {
+ counter += 1
+ counter
+ }
+}
+
+private[Chisel] trait HasId {
+ private[Chisel] def _onModuleClose {} // scalastyle:ignore method.name
+ private[Chisel] val _parent = Builder.dynamicContext.currentModule
+ _parent.foreach(_.addId(this))
+
+ private[Chisel] val _id = Builder.idGen.next
+ override def hashCode: Int = _id.toInt
+ override def equals(that: Any): Boolean = that match {
+ case x: HasId => _id == x._id
+ case _ => false
+ }
+
+ // Facilities for 'suggesting' a name to this.
+ // Post-name hooks called to carry the suggestion to other candidates as needed
+ private var suggested_name: Option[String] = None
+ private val postname_hooks = scala.collection.mutable.ListBuffer.empty[String=>Unit]
+ // Only takes the first suggestion!
+ def suggestName(name: =>String): this.type = {
+ if(suggested_name.isEmpty) suggested_name = Some(name)
+ for(hook <- postname_hooks) { hook(name) }
+ this
+ }
+ private[Chisel] def addPostnameHook(hook: String=>Unit): Unit = postname_hooks += hook
+
+ // Uses a namespace to convert suggestion into a true name
+ // Will not do any naming if the reference already assigned.
+ // (e.g. tried to suggest a name to part of a Bundle)
+ private[Chisel] def forceName(default: =>String, namespace: Namespace): Unit =
+ if(_ref.isEmpty) {
+ val candidate_name = suggested_name.getOrElse(default)
+ val available_name = namespace.name(candidate_name)
+ setRef(Ref(available_name))
+ }
+
+ private var _ref: Option[Arg] = None
+ private[Chisel] def setRef(imm: Arg): Unit = _ref = Some(imm)
+ private[Chisel] def setRef(parent: HasId, name: String): Unit = setRef(Slot(Node(parent), name))
+ private[Chisel] def setRef(parent: HasId, index: Int): Unit = setRef(Index(Node(parent), ILit(index)))
+ private[Chisel] def setRef(parent: HasId, index: UInt): Unit = setRef(Index(Node(parent), index.ref))
+ private[Chisel] def getRef: Arg = _ref.get
+}
+
+private[Chisel] class DynamicContext {
+ val idGen = new IdGen
+ val globalNamespace = new Namespace(None, Set())
+ val components = ArrayBuffer[Component]()
+ var currentModule: Option[Module] = None
+ val errors = new ErrorLog
+}
+
+private[Chisel] object Builder {
+ // All global mutable state must be referenced via dynamicContextVar!!
+ private val dynamicContextVar = new DynamicVariable[Option[DynamicContext]](None)
+
+ def dynamicContext: DynamicContext = dynamicContextVar.value.get
+ def idGen: IdGen = dynamicContext.idGen
+ def globalNamespace: Namespace = dynamicContext.globalNamespace
+ def components: ArrayBuffer[Component] = dynamicContext.components
+
+ def pushCommand[T <: Command](c: T): T = {
+ dynamicContext.currentModule.foreach(_._commands += c)
+ c
+ }
+ def pushOp[T <: Data](cmd: DefPrim[T]): T = pushCommand(cmd).id
+
+ def errors: ErrorLog = dynamicContext.errors
+ def error(m: => String): Unit = errors.error(m)
+
+ def build[T <: Module](f: => T): Circuit = {
+ dynamicContextVar.withValue(Some(new DynamicContext)) {
+ errors.info("Elaborating design...")
+ val mod = f
+ mod.forceName(mod.name, globalNamespace)
+ errors.checkpoint()
+ errors.info("Done elaborating.")
+
+ Circuit(components.last.name, components)
+ }
+ }
+}
diff --git a/chiselFrontend/src/main/scala/Chisel/internal/Error.scala b/chiselFrontend/src/main/scala/Chisel/internal/Error.scala
new file mode 100644
index 00000000..6c4c0880
--- /dev/null
+++ b/chiselFrontend/src/main/scala/Chisel/internal/Error.scala
@@ -0,0 +1,91 @@
+// See LICENSE for license details.
+
+package Chisel.internal
+
+import scala.collection.mutable.ArrayBuffer
+
+import Chisel._
+
+class ChiselException(message: String, cause: Throwable) extends Exception(message, cause)
+
+private[Chisel] object throwException {
+ def apply(s: String, t: Throwable = null): Nothing =
+ throw new ChiselException(s, t)
+}
+
+/** Records and reports runtime errors and warnings. */
+private[Chisel] class ErrorLog {
+ def hasErrors: Boolean = errors.exists(_.isFatal)
+
+ /** Log an error message */
+ def error(m: => String): Unit =
+ errors += new Error(m, getUserLineNumber)
+
+ /** Log a warning message */
+ def warning(m: => String): Unit =
+ errors += new Warning(m, getUserLineNumber)
+
+ /** Emit an informational message */
+ def info(m: String): Unit =
+ println(new Info("[%2.3f] %s".format(elapsedTime/1e3, m), None)) // scalastyle:ignore regex
+
+ /** Prints error messages generated by Chisel at runtime. */
+ def report(): Unit = errors foreach println // scalastyle:ignore regex
+
+ /** Throw an exception if any errors have yet occurred. */
+ def checkpoint(): Unit = if(hasErrors) {
+ import Console._
+ throwException(errors.map(_ + "\n").reduce(_ + _) +
+ UNDERLINED + "CODE HAS " + errors.filter(_.isFatal).length + RESET +
+ UNDERLINED + " " + RED + "ERRORS" + RESET +
+ UNDERLINED + " and " + errors.filterNot(_.isFatal).length + RESET +
+ UNDERLINED + " " + YELLOW + "WARNINGS" + RESET)
+ }
+
+ private def findFirstUserFrame(stack: Array[StackTraceElement]): Option[StackTraceElement] = {
+ def isUserCode(ste: StackTraceElement): Boolean = {
+ def isUserModule(c: Class[_]): Boolean =
+ c != null && (c == classOf[Module] || isUserModule(c.getSuperclass))
+ isUserModule(Class.forName(ste.getClassName))
+ }
+
+ stack.indexWhere(isUserCode) match {
+ case x if x < 0 => None
+ case x => Some(stack(x))
+ }
+ }
+
+ private def getUserLineNumber =
+ findFirstUserFrame(Thread.currentThread().getStackTrace)
+
+ private val errors = ArrayBuffer[LogEntry]()
+
+ private val startTime = System.currentTimeMillis
+ private def elapsedTime: Long = System.currentTimeMillis - startTime
+}
+
+private abstract class LogEntry(msg: => String, line: Option[StackTraceElement]) {
+ def isFatal: Boolean = false
+ def format: String
+
+ override def toString: String = line match {
+ case Some(l) => s"${format} ${l.getFileName}:${l.getLineNumber}: ${msg} in class ${l.getClassName}"
+ case None => s"${format} ${msg}"
+ }
+
+ protected def tag(name: String, color: String): String =
+ s"[${color}${name}${Console.RESET}]"
+}
+
+private class Error(msg: => String, line: Option[StackTraceElement]) extends LogEntry(msg, line) {
+ override def isFatal: Boolean = true
+ def format: String = tag("error", Console.RED)
+}
+
+private class Warning(msg: => String, line: Option[StackTraceElement]) extends LogEntry(msg, line) {
+ def format: String = tag("warn", Console.YELLOW)
+}
+
+private class Info(msg: => String, line: Option[StackTraceElement]) extends LogEntry(msg, line) {
+ def format: String = tag("info", Console.MAGENTA)
+}
diff --git a/chiselFrontend/src/main/scala/Chisel/internal/firrtl/Emitter.scala b/chiselFrontend/src/main/scala/Chisel/internal/firrtl/Emitter.scala
new file mode 100644
index 00000000..b690d974
--- /dev/null
+++ b/chiselFrontend/src/main/scala/Chisel/internal/firrtl/Emitter.scala
@@ -0,0 +1,101 @@
+// See LICENSE for license details.
+
+package Chisel.internal.firrtl
+import Chisel._
+
+private class Emitter(circuit: Circuit) {
+ override def toString: String = res.toString
+
+ private def emitPort(e: Port): String =
+ s"${e.dir} ${e.id.getRef.name} : ${e.id.toType}"
+ private def emit(e: Command, ctx: Component): String = e match {
+ case e: DefPrim[_] => s"node ${e.name} = ${e.op.name}(${e.args.map(_.fullName(ctx)).mkString(", ")})"
+ case e: DefWire => s"wire ${e.name} : ${e.id.toType}"
+ case e: DefReg => s"reg ${e.name} : ${e.id.toType}, ${e.clock.fullName(ctx)}"
+ case e: DefRegInit => s"reg ${e.name} : ${e.id.toType}, ${e.clock.fullName(ctx)} with : (reset => (${e.reset.fullName(ctx)}, ${e.init.fullName(ctx)}))"
+ case e: DefMemory => s"cmem ${e.name} : ${e.t.toType}[${e.size}]"
+ case e: DefSeqMemory => s"smem ${e.name} : ${e.t.toType}[${e.size}]"
+ case e: DefMemPort[_] => s"${e.dir} mport ${e.name} = ${e.source.fullName(ctx)}[${e.index.fullName(ctx)}], ${e.clock.fullName(ctx)}"
+ case e: Connect => s"${e.loc.fullName(ctx)} <= ${e.exp.fullName(ctx)}"
+ case e: BulkConnect => s"${e.loc1.fullName(ctx)} <- ${e.loc2.fullName(ctx)}"
+ case e: Stop => s"stop(${e.clk.fullName(ctx)}, UInt<1>(1), ${e.ret})"
+ case e: Printf => s"""printf(${e.clk.fullName(ctx)}, UInt<1>(1), "${e.format}"${e.ids.map(_.fullName(ctx)).fold(""){_ + ", " + _}})"""
+ case e: DefInvalid => s"${e.arg.fullName(ctx)} is invalid"
+ case e: DefInstance => {
+ val modName = moduleMap.get(e.id.name).get
+ s"inst ${e.name} of $modName"
+ }
+
+ case w: WhenBegin =>
+ indent()
+ s"when ${w.pred.fullName(ctx)} :"
+ case _: WhenEnd =>
+ unindent()
+ "skip"
+ }
+
+ // Map of Module FIRRTL definition to FIRRTL name, if it has been emitted already.
+ private val defnMap = collection.mutable.HashMap[String, String]()
+ // Map of Component name to FIRRTL id.
+ private val moduleMap = collection.mutable.HashMap[String, String]()
+
+ /** Generates the FIRRTL module definition with a specified name.
+ */
+ private def moduleDefn(m: Component, name: String): String = {
+ val body = new StringBuilder
+ m.id match {
+ case _: BlackBox => body ++= newline + s"extmodule $name : "
+ case _: Module => body ++= newline + s"module $name : "
+ }
+ withIndent {
+ for (p <- m.ports)
+ body ++= newline + emitPort(p)
+ body ++= newline
+
+ m.id match {
+ case _: BlackBox =>
+ // TODO: BlackBoxes should be empty, but funkiness in Module() means
+ // it's not for now. Eventually, this should assert out.
+ case _: Module => for (cmd <- m.commands) {
+ body ++= newline + emit(cmd, m)
+ }
+ }
+ body ++= newline
+ }
+ body.toString()
+ }
+
+ /** Returns the FIRRTL declaration and body of a module, or nothing if it's a
+ * duplicate of something already emitted (on the basis of simple string
+ * matching).
+ */
+ private def emit(m: Component): String = {
+ // Generate the body.
+ val moduleName = m.id.getClass.getName.split('.').last
+ val defn = moduleDefn(m, moduleName)
+
+ defnMap get defn match {
+ case Some(deduplicatedName) =>
+ moduleMap(m.name) = deduplicatedName
+ ""
+ case None =>
+ require(!(moduleMap contains m.name),
+ "emitting module with same name but different contents")
+
+ moduleMap(m.name) = m.name
+ defnMap(defn) = m.name
+
+ moduleDefn(m, m.name)
+ }
+ }
+
+ private var indentLevel = 0
+ private def newline = "\n" + (" " * indentLevel)
+ private def indent(): Unit = indentLevel += 1
+ private def unindent() { require(indentLevel > 0); indentLevel -= 1 }
+ private def withIndent(f: => Unit) { indent(); f; unindent() }
+
+ private val res = new StringBuilder(s"circuit ${circuit.name} : ")
+ withIndent { circuit.components.foreach(c => res ++= emit(c)) }
+ res ++= newline
+}
diff --git a/chiselFrontend/src/main/scala/Chisel/internal/firrtl/IR.scala b/chiselFrontend/src/main/scala/Chisel/internal/firrtl/IR.scala
new file mode 100644
index 00000000..1e06a663
--- /dev/null
+++ b/chiselFrontend/src/main/scala/Chisel/internal/firrtl/IR.scala
@@ -0,0 +1,187 @@
+// See LICENSE for license details.
+
+package Chisel.internal.firrtl
+import Chisel._
+import Chisel.internal._
+
+case class PrimOp(val name: String) {
+ override def toString: String = name
+}
+
+object PrimOp {
+ val AddOp = PrimOp("add")
+ val SubOp = PrimOp("sub")
+ val TailOp = PrimOp("tail")
+ val HeadOp = PrimOp("head")
+ val TimesOp = PrimOp("mul")
+ val DivideOp = PrimOp("div")
+ val RemOp = PrimOp("rem")
+ val ShiftLeftOp = PrimOp("shl")
+ val ShiftRightOp = PrimOp("shr")
+ val DynamicShiftLeftOp = PrimOp("dshl")
+ val DynamicShiftRightOp = PrimOp("dshr")
+ val BitAndOp = PrimOp("and")
+ val BitOrOp = PrimOp("or")
+ val BitXorOp = PrimOp("xor")
+ val BitNotOp = PrimOp("not")
+ val ConcatOp = PrimOp("cat")
+ 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 PadOp = PrimOp("pad")
+ val NotEqualOp = PrimOp("neq")
+ val NegOp = PrimOp("neg")
+ val MultiplexOp = PrimOp("mux")
+ val XorReduceOp = PrimOp("xorr")
+ val ConvertOp = PrimOp("cvt")
+ val AsUIntOp = PrimOp("asUInt")
+ val AsSIntOp = PrimOp("asSInt")
+}
+
+abstract class Arg {
+ def fullName(ctx: Component): String = name
+ def name: String
+}
+
+case class Node(id: HasId) extends Arg {
+ override def fullName(ctx: Component): String = id.getRef.fullName(ctx)
+ def name: String = id.getRef.name
+}
+
+abstract class LitArg(val num: BigInt, widthArg: Width) extends Arg {
+ private[Chisel] def forcedWidth = widthArg.known
+ private[Chisel] def width: Width = if (forcedWidth) widthArg else Width(minWidth)
+
+ protected def minWidth: Int
+ if (forcedWidth) {
+ require(widthArg.get >= minWidth,
+ s"The literal value ${num} was elaborated with a specificed width of ${widthArg.get} bits, but at least ${minWidth} bits are required.")
+ }
+}
+
+case class ILit(n: BigInt) extends Arg {
+ def name: String = n.toString
+}
+
+case class ULit(n: BigInt, w: Width) extends LitArg(n, w) {
+ def name: String = "UInt" + width + "(\"h0" + num.toString(16) + "\")"
+ def minWidth: Int = 1 max n.bitLength
+
+ require(n >= 0, s"UInt literal ${n} is negative")
+}
+
+case class SLit(n: BigInt, w: Width) extends LitArg(n, w) {
+ def name: String = {
+ val unsigned = if (n < 0) (BigInt(1) << width.get) + n else n
+ s"asSInt(${ULit(unsigned, width).name})"
+ }
+ def minWidth: Int = 1 + n.bitLength
+}
+
+case class Ref(name: String) extends Arg
+case class ModuleIO(mod: Module, name: String) extends Arg {
+ override def fullName(ctx: Component): String =
+ if (mod eq ctx.id) name else s"${mod.getRef.name}.$name"
+}
+case class Slot(imm: Node, name: String) extends Arg {
+ override def fullName(ctx: Component): String =
+ if (imm.fullName(ctx).isEmpty) name else s"${imm.fullName(ctx)}.${name}"
+}
+case class Index(imm: Arg, value: Arg) extends Arg {
+ def name: String = s"[$value]"
+ override def fullName(ctx: Component): String = s"${imm.fullName(ctx)}[${value.fullName(ctx)}]"
+}
+
+object Width {
+ def apply(x: Int): Width = KnownWidth(x)
+ def apply(): Width = UnknownWidth()
+}
+
+sealed abstract class Width {
+ type W = Int
+ def max(that: Width): Width = this.op(that, _ max _)
+ def + (that: Width): Width = this.op(that, _ + _)
+ def + (that: Int): Width = this.op(this, (a, b) => a + that)
+ def shiftRight(that: Int): Width = this.op(this, (a, b) => 0 max (a - that))
+ def dynamicShiftLeft(that: Width): Width =
+ this.op(that, (a, b) => a + (1 << b) - 1)
+
+ def known: Boolean
+ def get: W
+ protected def op(that: Width, f: (W, W) => W): Width
+}
+
+sealed case class UnknownWidth() extends Width {
+ def known: Boolean = false
+ def get: Int = None.get
+ def op(that: Width, f: (W, W) => W): Width = this
+ override def toString: String = ""
+}
+
+sealed case class KnownWidth(value: Int) extends Width {
+ require(value >= 0)
+ def known: Boolean = true
+ def get: Int = value
+ def op(that: Width, f: (W, W) => W): Width = that match {
+ case KnownWidth(x) => KnownWidth(f(value, x))
+ case _ => that
+ }
+ override def toString: String = s"<${value.toString}>"
+}
+
+sealed abstract class MemPortDirection(name: String) {
+ override def toString: String = name
+}
+object MemPortDirection {
+ object READ extends MemPortDirection("read")
+ object WRITE extends MemPortDirection("write")
+ object RDWR extends MemPortDirection("rdwr")
+ object INFER extends MemPortDirection("infer")
+}
+
+abstract class Command
+abstract class Definition extends Command {
+ def id: HasId
+ def name: String = id.getRef.name
+}
+case class DefPrim[T <: Data](id: T, op: PrimOp, args: Arg*) extends Definition
+case class DefInvalid(arg: Arg) extends Command
+case class DefWire(id: Data) extends Definition
+case class DefReg(id: Data, clock: Arg) extends Definition
+case class DefRegInit(id: Data, clock: Arg, reset: Arg, init: Arg) extends Definition
+case class DefMemory(id: HasId, t: Data, size: Int) extends Definition
+case class DefSeqMemory(id: HasId, t: Data, size: Int) extends Definition
+case class DefMemPort[T <: Data](id: T, source: Node, dir: MemPortDirection, index: Arg, clock: Arg) extends Definition
+case class DefInstance(id: Module, ports: Seq[Port]) extends Definition
+case class WhenBegin(pred: Arg) extends Command
+case class WhenEnd() extends Command
+case class Connect(loc: Node, exp: Arg) extends Command
+case class BulkConnect(loc1: Node, loc2: Node) extends Command
+case class ConnectInit(loc: Node, exp: Arg) extends Command
+case class Stop(clk: Arg, ret: Int) extends Command
+case class Component(id: Module, name: String, ports: Seq[Port], commands: Seq[Command]) extends Arg
+case class Port(id: Data, dir: Direction)
+case class Printf(clk: Arg, formatIn: String, ids: Seq[Arg]) extends Command {
+ require(formatIn.forall(c => c.toInt > 0 && c.toInt < 128), "format strings must comprise non-null ASCII values")
+ def format: String = {
+ def escaped(x: Char) = {
+ require(x.toInt >= 0)
+ if (x == '"' || x == '\\') {
+ s"\\${x}"
+ } else if (x == '\n') {
+ "\\n"
+ } else {
+ require(x.toInt >= 32) // TODO \xNN once FIRRTL issue #59 is resolved
+ x
+ }
+ }
+ formatIn.map(escaped _).mkString
+ }
+}
+
+case class Circuit(name: String, components: Seq[Component]) {
+ def emit: String = new Emitter(this).toString
+}