From c5f9ea3133ef363ff8944e17d94fea79767b6bed Mon Sep 17 00:00:00 2001 From: Jim Lawson Date: Wed, 6 Jul 2016 10:01:23 -0700 Subject: Rename "Chisel" to "chisel3" (only git mv). --- .../src/main/scala/Chisel/Aggregate.scala | 377 ---------- chiselFrontend/src/main/scala/Chisel/Assert.scala | 73 -- chiselFrontend/src/main/scala/Chisel/Bits.scala | 756 --------------------- .../src/main/scala/Chisel/BlackBox.scala | 55 -- chiselFrontend/src/main/scala/Chisel/Data.scala | 161 ----- chiselFrontend/src/main/scala/Chisel/Mem.scala | 134 ---- chiselFrontend/src/main/scala/Chisel/Module.scala | 119 ---- chiselFrontend/src/main/scala/Chisel/Printf.scala | 36 - chiselFrontend/src/main/scala/Chisel/Reg.scala | 71 -- .../src/main/scala/Chisel/SeqUtils.scala | 59 -- chiselFrontend/src/main/scala/Chisel/When.scala | 59 -- .../src/main/scala/Chisel/internal/Builder.scala | 123 ---- .../src/main/scala/Chisel/internal/Error.scala | 91 --- .../main/scala/Chisel/internal/SourceInfo.scala | 51 -- .../src/main/scala/Chisel/internal/firrtl/IR.scala | 188 ----- .../src/main/scala/chisel3/core/Aggregate.scala | 377 ++++++++++ .../src/main/scala/chisel3/core/Assert.scala | 73 ++ .../src/main/scala/chisel3/core/BiConnect.scala | 190 ++++++ .../src/main/scala/chisel3/core/Binder.scala | 64 ++ .../src/main/scala/chisel3/core/Binding.scala | 179 +++++ .../src/main/scala/chisel3/core/Bits.scala | 756 +++++++++++++++++++++ .../src/main/scala/chisel3/core/BlackBox.scala | 55 ++ .../src/main/scala/chisel3/core/Data.scala | 161 +++++ .../src/main/scala/chisel3/core/Mem.scala | 134 ++++ .../src/main/scala/chisel3/core/Module.scala | 119 ++++ .../src/main/scala/chisel3/core/MonoConnect.scala | 172 +++++ .../src/main/scala/chisel3/core/Printf.scala | 36 + .../src/main/scala/chisel3/core/Reg.scala | 71 ++ .../src/main/scala/chisel3/core/SeqUtils.scala | 59 ++ .../src/main/scala/chisel3/core/When.scala | 59 ++ .../src/main/scala/chisel3/internal/Builder.scala | 123 ++++ .../src/main/scala/chisel3/internal/Error.scala | 91 +++ .../main/scala/chisel3/internal/SourceInfo.scala | 51 ++ .../main/scala/chisel3/internal/firrtl/IR.scala | 188 +++++ .../internal/sourceinfo/SourceInfoTransform.scala | 156 ----- .../internal/sourceinfo/SourceInfoTransform.scala | 156 +++++ src/main/scala/Chisel/BitPat.scala | 88 --- src/main/scala/Chisel/Driver.scala | 132 ---- src/main/scala/Chisel/FileSystemUtilities.scala | 10 - src/main/scala/Chisel/ImplicitConversions.scala | 8 - src/main/scala/Chisel/Main.scala | 17 - .../scala/Chisel/internal/firrtl/Emitter.scala | 112 --- src/main/scala/Chisel/package.scala | 31 - src/main/scala/Chisel/testers/BasicTester.scala | 38 -- src/main/scala/Chisel/testers/TesterDriver.scala | 68 -- src/main/scala/Chisel/throwException.scala | 12 - src/main/scala/Chisel/util/Arbiter.scala | 117 ---- src/main/scala/Chisel/util/Bitwise.scala | 71 -- src/main/scala/Chisel/util/Cat.scala | 18 - src/main/scala/Chisel/util/CircuitMath.scala | 26 - src/main/scala/Chisel/util/Conditional.scala | 69 -- src/main/scala/Chisel/util/Counter.scala | 44 -- src/main/scala/Chisel/util/Decoupled.scala | 183 ----- src/main/scala/Chisel/util/Enum.scala | 21 - src/main/scala/Chisel/util/LFSR.scala | 22 - src/main/scala/Chisel/util/Lookup.scala | 17 - src/main/scala/Chisel/util/Math.scala | 42 -- src/main/scala/Chisel/util/Mux.scala | 61 -- src/main/scala/Chisel/util/OneHot.scala | 62 -- src/main/scala/Chisel/util/Reg.scala | 55 -- src/main/scala/Chisel/util/TransitName.scala | 21 - src/main/scala/Chisel/util/Valid.scala | 59 -- src/main/scala/chisel3/Driver.scala | 132 ++++ .../compatibility/FileSystemUtilities.scala | 10 + src/main/scala/chisel3/compatibility/Main.scala | 17 + .../chisel3/compatibility/throwException.scala | 12 + .../scala/chisel3/internal/firrtl/Emitter.scala | 112 +++ src/main/scala/chisel3/package.scala | 31 + src/main/scala/chisel3/testers/BasicTester.scala | 38 ++ src/main/scala/chisel3/testers/TesterDriver.scala | 68 ++ src/main/scala/chisel3/util/Arbiter.scala | 117 ++++ src/main/scala/chisel3/util/BitPat.scala | 88 +++ src/main/scala/chisel3/util/Bitwise.scala | 71 ++ src/main/scala/chisel3/util/Cat.scala | 18 + src/main/scala/chisel3/util/CircuitMath.scala | 26 + src/main/scala/chisel3/util/Conditional.scala | 69 ++ src/main/scala/chisel3/util/Counter.scala | 44 ++ src/main/scala/chisel3/util/Decoupled.scala | 183 +++++ src/main/scala/chisel3/util/Enum.scala | 21 + .../scala/chisel3/util/ImplicitConversions.scala | 8 + src/main/scala/chisel3/util/LFSR.scala | 22 + src/main/scala/chisel3/util/Lookup.scala | 17 + src/main/scala/chisel3/util/Math.scala | 42 ++ src/main/scala/chisel3/util/Mux.scala | 61 ++ src/main/scala/chisel3/util/OneHot.scala | 62 ++ src/main/scala/chisel3/util/Reg.scala | 55 ++ src/main/scala/chisel3/util/TransitName.scala | 21 + src/main/scala/chisel3/util/Valid.scala | 59 ++ 88 files changed, 4518 insertions(+), 3913 deletions(-) delete mode 100644 chiselFrontend/src/main/scala/Chisel/Aggregate.scala delete mode 100644 chiselFrontend/src/main/scala/Chisel/Assert.scala delete mode 100644 chiselFrontend/src/main/scala/Chisel/Bits.scala delete mode 100644 chiselFrontend/src/main/scala/Chisel/BlackBox.scala delete mode 100644 chiselFrontend/src/main/scala/Chisel/Data.scala delete mode 100644 chiselFrontend/src/main/scala/Chisel/Mem.scala delete mode 100644 chiselFrontend/src/main/scala/Chisel/Module.scala delete mode 100644 chiselFrontend/src/main/scala/Chisel/Printf.scala delete mode 100644 chiselFrontend/src/main/scala/Chisel/Reg.scala delete mode 100644 chiselFrontend/src/main/scala/Chisel/SeqUtils.scala delete mode 100644 chiselFrontend/src/main/scala/Chisel/When.scala delete mode 100644 chiselFrontend/src/main/scala/Chisel/internal/Builder.scala delete mode 100644 chiselFrontend/src/main/scala/Chisel/internal/Error.scala delete mode 100644 chiselFrontend/src/main/scala/Chisel/internal/SourceInfo.scala delete mode 100644 chiselFrontend/src/main/scala/Chisel/internal/firrtl/IR.scala create mode 100644 chiselFrontend/src/main/scala/chisel3/core/Aggregate.scala create mode 100644 chiselFrontend/src/main/scala/chisel3/core/Assert.scala create mode 100644 chiselFrontend/src/main/scala/chisel3/core/BiConnect.scala create mode 100644 chiselFrontend/src/main/scala/chisel3/core/Binder.scala create mode 100644 chiselFrontend/src/main/scala/chisel3/core/Binding.scala create mode 100644 chiselFrontend/src/main/scala/chisel3/core/Bits.scala create mode 100644 chiselFrontend/src/main/scala/chisel3/core/BlackBox.scala create mode 100644 chiselFrontend/src/main/scala/chisel3/core/Data.scala create mode 100644 chiselFrontend/src/main/scala/chisel3/core/Mem.scala create mode 100644 chiselFrontend/src/main/scala/chisel3/core/Module.scala create mode 100644 chiselFrontend/src/main/scala/chisel3/core/MonoConnect.scala create mode 100644 chiselFrontend/src/main/scala/chisel3/core/Printf.scala create mode 100644 chiselFrontend/src/main/scala/chisel3/core/Reg.scala create mode 100644 chiselFrontend/src/main/scala/chisel3/core/SeqUtils.scala create mode 100644 chiselFrontend/src/main/scala/chisel3/core/When.scala create mode 100644 chiselFrontend/src/main/scala/chisel3/internal/Builder.scala create mode 100644 chiselFrontend/src/main/scala/chisel3/internal/Error.scala create mode 100644 chiselFrontend/src/main/scala/chisel3/internal/SourceInfo.scala create mode 100644 chiselFrontend/src/main/scala/chisel3/internal/firrtl/IR.scala delete mode 100644 coreMacros/src/main/scala/Chisel/internal/sourceinfo/SourceInfoTransform.scala create mode 100644 coreMacros/src/main/scala/chisel3/internal/sourceinfo/SourceInfoTransform.scala delete mode 100644 src/main/scala/Chisel/BitPat.scala delete mode 100644 src/main/scala/Chisel/Driver.scala delete mode 100644 src/main/scala/Chisel/FileSystemUtilities.scala delete mode 100644 src/main/scala/Chisel/ImplicitConversions.scala delete mode 100644 src/main/scala/Chisel/Main.scala delete mode 100644 src/main/scala/Chisel/internal/firrtl/Emitter.scala delete mode 100644 src/main/scala/Chisel/package.scala delete mode 100644 src/main/scala/Chisel/testers/BasicTester.scala delete mode 100644 src/main/scala/Chisel/testers/TesterDriver.scala delete mode 100644 src/main/scala/Chisel/throwException.scala delete mode 100644 src/main/scala/Chisel/util/Arbiter.scala delete mode 100644 src/main/scala/Chisel/util/Bitwise.scala delete mode 100644 src/main/scala/Chisel/util/Cat.scala delete mode 100644 src/main/scala/Chisel/util/CircuitMath.scala delete mode 100644 src/main/scala/Chisel/util/Conditional.scala delete mode 100644 src/main/scala/Chisel/util/Counter.scala delete mode 100644 src/main/scala/Chisel/util/Decoupled.scala delete mode 100644 src/main/scala/Chisel/util/Enum.scala delete mode 100644 src/main/scala/Chisel/util/LFSR.scala delete mode 100644 src/main/scala/Chisel/util/Lookup.scala delete mode 100644 src/main/scala/Chisel/util/Math.scala delete mode 100644 src/main/scala/Chisel/util/Mux.scala delete mode 100644 src/main/scala/Chisel/util/OneHot.scala delete mode 100644 src/main/scala/Chisel/util/Reg.scala delete mode 100644 src/main/scala/Chisel/util/TransitName.scala delete mode 100644 src/main/scala/Chisel/util/Valid.scala create mode 100644 src/main/scala/chisel3/Driver.scala create mode 100644 src/main/scala/chisel3/compatibility/FileSystemUtilities.scala create mode 100644 src/main/scala/chisel3/compatibility/Main.scala create mode 100644 src/main/scala/chisel3/compatibility/throwException.scala create mode 100644 src/main/scala/chisel3/internal/firrtl/Emitter.scala create mode 100644 src/main/scala/chisel3/package.scala create mode 100644 src/main/scala/chisel3/testers/BasicTester.scala create mode 100644 src/main/scala/chisel3/testers/TesterDriver.scala create mode 100644 src/main/scala/chisel3/util/Arbiter.scala create mode 100644 src/main/scala/chisel3/util/BitPat.scala create mode 100644 src/main/scala/chisel3/util/Bitwise.scala create mode 100644 src/main/scala/chisel3/util/Cat.scala create mode 100644 src/main/scala/chisel3/util/CircuitMath.scala create mode 100644 src/main/scala/chisel3/util/Conditional.scala create mode 100644 src/main/scala/chisel3/util/Counter.scala create mode 100644 src/main/scala/chisel3/util/Decoupled.scala create mode 100644 src/main/scala/chisel3/util/Enum.scala create mode 100644 src/main/scala/chisel3/util/ImplicitConversions.scala create mode 100644 src/main/scala/chisel3/util/LFSR.scala create mode 100644 src/main/scala/chisel3/util/Lookup.scala create mode 100644 src/main/scala/chisel3/util/Math.scala create mode 100644 src/main/scala/chisel3/util/Mux.scala create mode 100644 src/main/scala/chisel3/util/OneHot.scala create mode 100644 src/main/scala/chisel3/util/Reg.scala create mode 100644 src/main/scala/chisel3/util/TransitName.scala create mode 100644 src/main/scala/chisel3/util/Valid.scala diff --git a/chiselFrontend/src/main/scala/Chisel/Aggregate.scala b/chiselFrontend/src/main/scala/Chisel/Aggregate.scala deleted file mode 100644 index 1eef5d69..00000000 --- a/chiselFrontend/src/main/scala/Chisel/Aggregate.scala +++ /dev/null @@ -1,377 +0,0 @@ -// See LICENSE for license details. - -package Chisel - -import scala.collection.immutable.ListMap -import scala.collection.mutable.{ArrayBuffer, HashSet, LinkedHashMap} -import scala.language.experimental.macros - -import internal._ -import internal.Builder.pushCommand -import internal.firrtl._ -import internal.sourceinfo.{SourceInfo, DeprecatedSourceInfo, VecTransform, SourceInfoTransform} - -/** 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] = macro VecTransform.apply_elts - - def do_apply[T <: Data](elts: Seq[T])(implicit sourceInfo: SourceInfo): 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] = macro VecTransform.apply_elt0 - - def do_apply[T <: Data](elt0: T, elts: T*)(implicit sourceInfo: SourceInfo): 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] = macro VecTransform.tabulate - - def do_tabulate[T <: Data](n: Int)(gen: (Int) => T)(implicit sourceInfo: SourceInfo): 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] = macro VecTransform.fill - - def do_fill[T <: Data](n: Int)(gen: => T)(implicit sourceInfo: SourceInfo): 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)(implicit sourceInfo: SourceInfo): 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])(implicit sourceInfo: SourceInfo): Unit = this := that - - // TODO: eliminate once assign(Seq) isn't ambiguous with assign(Data) since Vec extends Seq and Data - def <> (that: Vec[T])(implicit sourceInfo: SourceInfo): Unit = this := that.asInstanceOf[Data] - - override def := (that: Data)(implicit sourceInfo: SourceInfo): 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])(implicit sourceInfo: SourceInfo): 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])(implicit sourceInfo: SourceInfo): 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)(DeprecatedSourceInfo) - - 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] with HasId { - def apply(idx: UInt): T - - // IndexedSeq has its own hashCode/equals that we must not use - override def hashCode: Int = super[HasId].hashCode - override def equals(that: Any): Boolean = super[HasId].equals(that) - - @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 = macro SourceInfoTransform.pArg - - def do_forall(p: T => Bool)(implicit sourceInfo: SourceInfo): Bool = - (this map p).fold(Bool(true))(_ && _) - - /** Outputs true if p outputs true for at least one element. - */ - def exists(p: T => Bool): Bool = macro SourceInfoTransform.pArg - - def do_exists(p: T => Bool)(implicit sourceInfo: SourceInfo): 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 ev: T <:< UInt): Bool = macro VecTransform.contains - - def do_contains(x: T)(implicit sourceInfo: SourceInfo, ev: T <:< UInt): Bool = - this.exists(_ === x) - - /** Outputs the number of elements for which p is true. - */ - def count(p: T => Bool): UInt = macro SourceInfoTransform.pArg - - def do_count(p: T => Bool)(implicit sourceInfo: SourceInfo): 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 = macro SourceInfoTransform.pArg - - def do_indexWhere(p: T => Bool)(implicit sourceInfo: SourceInfo): UInt = - SeqUtils.priorityMux(indexWhereHelper(p)) - - /** Outputs the index of the last element for which p outputs true. - */ - def lastIndexWhere(p: T => Bool): UInt = macro SourceInfoTransform.pArg - - def do_lastIndexWhere(p: T => Bool)(implicit sourceInfo: SourceInfo): 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 = macro SourceInfoTransform.pArg - - def do_onlyIndexWhere(p: T => Bool)(implicit sourceInfo: SourceInfo): 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)(implicit sourceInfo: SourceInfo): 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)(implicit sourceInfo: SourceInfo): 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/Assert.scala b/chiselFrontend/src/main/scala/Chisel/Assert.scala deleted file mode 100644 index c086f014..00000000 --- a/chiselFrontend/src/main/scala/Chisel/Assert.scala +++ /dev/null @@ -1,73 +0,0 @@ -// See LICENSE for license details. - -package Chisel - -import scala.reflect.macros.blackbox.Context -import scala.language.experimental.macros - -import internal._ -import internal.Builder.pushCommand -import internal.firrtl._ -import internal.sourceinfo.SourceInfo - -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 - */ - // Macros currently can't take default arguments, so we need two functions to emulate defaults. - def apply(cond: Bool, message: String)(implicit sourceInfo: SourceInfo): Unit = macro apply_impl_msg - def apply(cond: Bool)(implicit sourceInfo: SourceInfo): Unit = macro apply_impl - - def apply_impl_msg(c: Context)(cond: c.Tree, message: c.Tree)(sourceInfo: 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))($sourceInfo)" - } - - def apply_impl(c: Context)(cond: c.Tree)(sourceInfo: 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)($sourceInfo)" - } - - def apply_impl_do(cond: Bool, line: String, message: Option[String])(implicit sourceInfo: SourceInfo) { - 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(sourceInfo, 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, "") - } -} diff --git a/chiselFrontend/src/main/scala/Chisel/Bits.scala b/chiselFrontend/src/main/scala/Chisel/Bits.scala deleted file mode 100644 index bc8cc8e2..00000000 --- a/chiselFrontend/src/main/scala/Chisel/Bits.scala +++ /dev/null @@ -1,756 +0,0 @@ -// See LICENSE for license details. - -package Chisel - -import scala.language.experimental.macros - -import internal._ -import internal.Builder.pushOp -import internal.firrtl._ -import internal.sourceinfo.{SourceInfo, DeprecatedSourceInfo, SourceInfoTransform, SourceInfoWhiteboxTransform, - UIntTransform, MuxTransform} -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, w: Int): this.type - - private[Chisel] def flatten: IndexedSeq[Bits] = IndexedSeq(this) - - def cloneType: this.type = cloneTypeWidth(width) - - override def <> (that: Data)(implicit sourceInfo: SourceInfo): Unit = this := that - - final def tail(n: Int): UInt = macro SourceInfoTransform.nArg - final def head(n: Int): UInt = macro SourceInfoTransform.nArg - - def do_tail(n: Int)(implicit sourceInfo: SourceInfo): 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(sourceInfo, UInt(width = w), TailOp, n) - } - - - def do_head(n: Int)(implicit sourceInfo: SourceInfo): UInt = { - width match { - case KnownWidth(x) => require(x >= n, s"Can't head($n) for width $x < $n") - case UnknownWidth() => - } - binop(sourceInfo, UInt(width = n), HeadOp, n) - } - - /** Returns the specified bit on this wire as a [[Bool]], statically - * addressed. - */ - final def apply(x: BigInt): Bool = macro SourceInfoTransform.xArg - - final def do_apply(x: BigInt)(implicit sourceInfo: SourceInfo): 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(sourceInfo, 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 = macro SourceInfoTransform.xArg - - final def do_apply(x: Int)(implicit sourceInfo: SourceInfo): Bool = apply(BigInt(x)) - - /** Returns the specified bit on this wire as a [[Bool]], dynamically - * addressed. - */ - final def apply(x: UInt): Bool = macro SourceInfoTransform.xArg - - final def do_apply(x: UInt)(implicit sourceInfo: SourceInfo): 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 = macro SourceInfoTransform.xyArg - - final def do_apply(x: Int, y: Int)(implicit sourceInfo: SourceInfo): 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(sourceInfo, 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 = macro SourceInfoTransform.xyArg - - final def do_apply(x: BigInt, y: BigInt)(implicit sourceInfo: SourceInfo): UInt = - apply(x.toInt, y.toInt) - - private[Chisel] def unop[T <: Data](sourceInfo: SourceInfo, dest: T, op: PrimOp): T = - pushOp(DefPrim(sourceInfo, dest, op, this.ref)) - private[Chisel] def binop[T <: Data](sourceInfo: SourceInfo, dest: T, op: PrimOp, other: BigInt): T = - pushOp(DefPrim(sourceInfo, dest, op, this.ref, ILit(other))) - private[Chisel] def binop[T <: Data](sourceInfo: SourceInfo, dest: T, op: PrimOp, other: Bits): T = - pushOp(DefPrim(sourceInfo, dest, op, this.ref, other.ref)) - - private[Chisel] def compop(sourceInfo: SourceInfo, op: PrimOp, other: Bits): Bool = - pushOp(DefPrim(sourceInfo, Bool(), op, this.ref, other.ref)) - private[Chisel] def redop(sourceInfo: SourceInfo, op: PrimOp): Bool = - pushOp(DefPrim(sourceInfo, Bool(), op, this.ref)) - - /** Returns this wire zero padded up to the specified width. - * - * @note for SInts only, this does sign extension - */ - final def pad(that: Int): this.type = macro SourceInfoTransform.thatArg - - def do_pad(that: Int)(implicit sourceInfo: SourceInfo): this.type = - binop(sourceInfo, cloneTypeWidth(this.width max Width(that)), PadOp, that) - - /** Returns this wire bitwise-inverted. */ - final def unary_~ (): Bits = macro SourceInfoWhiteboxTransform.noArg - - def do_unary_~ (implicit sourceInfo: SourceInfo): Bits - - - /** Shift left operation */ - // REVIEW TODO: redundant - // REVIEW TODO: should these return this.type or Bits? - final def << (that: BigInt): Bits = macro SourceInfoWhiteboxTransform.thatArg - - def do_<< (that: BigInt)(implicit sourceInfo: SourceInfo): 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. - */ - final def << (that: Int): Bits = macro SourceInfoWhiteboxTransform.thatArg - - def do_<< (that: Int)(implicit sourceInfo: SourceInfo): 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. - */ - final def << (that: UInt): Bits = macro SourceInfoWhiteboxTransform.thatArg - - def do_<< (that: UInt)(implicit sourceInfo: SourceInfo): Bits - - /** Shift right operation */ - // REVIEW TODO: redundant - final def >> (that: BigInt): Bits = macro SourceInfoWhiteboxTransform.thatArg - - def do_>> (that: BigInt)(implicit sourceInfo: SourceInfo): 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. - */ - final def >> (that: Int): Bits = macro SourceInfoWhiteboxTransform.thatArg - - def do_>> (that: Int)(implicit sourceInfo: SourceInfo): 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. - */ - final def >> (that: UInt): Bits = macro SourceInfoWhiteboxTransform.thatArg - - def do_>> (that: UInt)(implicit sourceInfo: SourceInfo): Bits - - /** Returns the contents of this wire as a [[Vec]] of [[Bool]]s. - */ - final def toBools(): Seq[Bool] = macro SourceInfoTransform.noArg - - def toBools(implicit sourceInfo: SourceInfo): Seq[Bool] = - Seq.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 - */ - final def asSInt(): SInt = macro SourceInfoTransform.noArg - - def do_asSInt(implicit sourceInfo: SourceInfo): 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 - */ - final def asUInt(): UInt = macro SourceInfoTransform.noArg - - def do_asUInt(implicit sourceInfo: SourceInfo): UInt - - /** Reinterpret cast to Bits. */ - final def asBits(): Bits = macro SourceInfoTransform.noArg - - def do_asBits(implicit sourceInfo: SourceInfo): Bits = asUInt() - - @deprecated("Use asSInt, which makes the reinterpret cast more explicit", "chisel3") - final def toSInt(): SInt = do_asSInt(DeprecatedSourceInfo) - @deprecated("Use asUInt, which makes the reinterpret cast more explicit", "chisel3") - final def toUInt(): UInt = do_asUInt(DeprecatedSourceInfo) - - final def toBool(): Bool = macro SourceInfoTransform.noArg - - def do_toBool(implicit sourceInfo: SourceInfo): 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. - */ - final def ## (that: Bits): UInt = macro SourceInfoTransform.thatArg - - def do_## (that: Bits)(implicit sourceInfo: SourceInfo): UInt = { - val w = this.width + that.width - pushOp(DefPrim(sourceInfo, UInt(w), ConcatOp, this.ref, that.ref)) - } - - @deprecated("Use asBits, which makes the reinterpret cast more explicit and actually returns Bits", "chisel3") - override def toBits: UInt = do_asUInt(DeprecatedSourceInfo) - - override def do_fromBits(that: Bits)(implicit sourceInfo: SourceInfo): this.type = { - val res = Wire(this, null).asInstanceOf[this.type] - res := that - 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). - */ - final def + (that: T): T = macro SourceInfoTransform.thatArg - - def do_+ (that: T)(implicit sourceInfo: SourceInfo): 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 - */ - final def * (that: T): T = macro SourceInfoTransform.thatArg - - def do_* (that: T)(implicit sourceInfo: SourceInfo): T - - /** Outputs the quotient of `this` and `b`. - * - * TODO: full rules - */ - final def / (that: T): T = macro SourceInfoTransform.thatArg - - def do_/ (that: T)(implicit sourceInfo: SourceInfo): T - - final def % (that: T): T = macro SourceInfoTransform.thatArg - - def do_% (that: T)(implicit sourceInfo: SourceInfo): T - - /** Outputs the difference of `this` and `b`. The resulting width is the max - * of the operands plus 1 (should not overflow). - */ - final def - (that: T): T = macro SourceInfoTransform.thatArg - - def do_- (that: T)(implicit sourceInfo: SourceInfo): T - - /** Outputs true if `this` < `b`. - */ - final def < (that: T): Bool = macro SourceInfoTransform.thatArg - - def do_< (that: T)(implicit sourceInfo: SourceInfo): Bool - - /** Outputs true if `this` <= `b`. - */ - final def <= (that: T): Bool = macro SourceInfoTransform.thatArg - - def do_<= (that: T)(implicit sourceInfo: SourceInfo): Bool - - /** Outputs true if `this` > `b`. - */ - final def > (that: T): Bool = macro SourceInfoTransform.thatArg - - def do_> (that: T)(implicit sourceInfo: SourceInfo): Bool - - /** Outputs true if `this` >= `b`. - */ - final def >= (that: T): Bool = macro SourceInfoTransform.thatArg - - def do_>= (that: T)(implicit sourceInfo: SourceInfo): Bool - - /** Outputs the minimum of `this` and `b`. The resulting width is the max of - * the operands. - */ - final def min(that: T): T = macro SourceInfoTransform.thatArg - - def do_min(that: T)(implicit sourceInfo: SourceInfo): T = - Mux(this < that, this.asInstanceOf[T], that) - - /** Outputs the maximum of `this` and `b`. The resulting width is the max of - * the operands. - */ - final def max(that: T): T = macro SourceInfoTransform.thatArg - - def do_max(that: T)(implicit sourceInfo: SourceInfo): T = - Mux(this < that, that, 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, width: Int): this.type = - UInt(value, width).asInstanceOf[this.type] - - override def := (that: Data)(implicit sourceInfo: SourceInfo): Unit = that match { - case _: UInt => this connect that - case _ => this badConnect that - } - - // TODO: refactor to share documentation with Num or add independent scaladoc - final def unary_- (): UInt = macro SourceInfoTransform.noArg - final def unary_-% (): UInt = macro SourceInfoTransform.noArg - - def do_unary_- (implicit sourceInfo: SourceInfo) : UInt = UInt(0) - this - def do_unary_-% (implicit sourceInfo: SourceInfo): UInt = UInt(0) -% this - - override def do_+ (that: UInt)(implicit sourceInfo: SourceInfo): UInt = this +% that - override def do_- (that: UInt)(implicit sourceInfo: SourceInfo): UInt = this -% that - override def do_/ (that: UInt)(implicit sourceInfo: SourceInfo): UInt = - binop(sourceInfo, UInt(this.width), DivideOp, that) - override def do_% (that: UInt)(implicit sourceInfo: SourceInfo): UInt = - binop(sourceInfo, UInt(this.width), RemOp, that) - override def do_* (that: UInt)(implicit sourceInfo: SourceInfo): UInt = - binop(sourceInfo, UInt(this.width + that.width), TimesOp, that) - - final def * (that: SInt): SInt = macro SourceInfoTransform.thatArg - def do_* (that: SInt)(implicit sourceInfo: SourceInfo): SInt = that * this - - final def +& (that: UInt): UInt = macro SourceInfoTransform.thatArg - final def +% (that: UInt): UInt = macro SourceInfoTransform.thatArg - final def -& (that: UInt): UInt = macro SourceInfoTransform.thatArg - final def -% (that: UInt): UInt = macro SourceInfoTransform.thatArg - - def do_+& (that: UInt)(implicit sourceInfo: SourceInfo): UInt = - binop(sourceInfo, UInt((this.width max that.width) + 1), AddOp, that) - def do_+% (that: UInt)(implicit sourceInfo: SourceInfo): UInt = - (this +& that).tail(1) - def do_-& (that: UInt)(implicit sourceInfo: SourceInfo): UInt = - binop(sourceInfo, UInt((this.width max that.width) + 1), SubOp, that) - def do_-% (that: UInt)(implicit sourceInfo: SourceInfo): UInt = - (this -& that).tail(1) - - final def & (that: UInt): UInt = macro SourceInfoTransform.thatArg - final def | (that: UInt): UInt = macro SourceInfoTransform.thatArg - final def ^ (that: UInt): UInt = macro SourceInfoTransform.thatArg - - def do_& (that: UInt)(implicit sourceInfo: SourceInfo): UInt = - binop(sourceInfo, UInt(this.width max that.width), BitAndOp, that) - def do_| (that: UInt)(implicit sourceInfo: SourceInfo): UInt = - binop(sourceInfo, UInt(this.width max that.width), BitOrOp, that) - def do_^ (that: UInt)(implicit sourceInfo: SourceInfo): UInt = - binop(sourceInfo, UInt(this.width max that.width), BitXorOp, that) - - /** Returns this wire bitwise-inverted. */ - def do_unary_~ (implicit sourceInfo: SourceInfo): UInt = - unop(sourceInfo, UInt(width = width), BitNotOp) - - // REVIEW TODO: Can this be defined on Bits? - final def orR(): Bool = macro SourceInfoTransform.noArg - final def andR(): Bool = macro SourceInfoTransform.noArg - final def xorR(): Bool = macro SourceInfoTransform.noArg - - def do_orR(implicit sourceInfo: SourceInfo): Bool = this != UInt(0) - def do_andR(implicit sourceInfo: SourceInfo): Bool = ~this === UInt(0) - def do_xorR(implicit sourceInfo: SourceInfo): Bool = redop(sourceInfo, XorReduceOp) - - override def do_< (that: UInt)(implicit sourceInfo: SourceInfo): Bool = compop(sourceInfo, LessOp, that) - override def do_> (that: UInt)(implicit sourceInfo: SourceInfo): Bool = compop(sourceInfo, GreaterOp, that) - override def do_<= (that: UInt)(implicit sourceInfo: SourceInfo): Bool = compop(sourceInfo, LessEqOp, that) - override def do_>= (that: UInt)(implicit sourceInfo: SourceInfo): Bool = compop(sourceInfo, GreaterEqOp, that) - - final def != (that: UInt): Bool = macro SourceInfoTransform.thatArg - final def =/= (that: UInt): Bool = macro SourceInfoTransform.thatArg - final def === (that: UInt): Bool = macro SourceInfoTransform.thatArg - - def do_!= (that: UInt)(implicit sourceInfo: SourceInfo): Bool = compop(sourceInfo, NotEqualOp, that) - def do_=/= (that: UInt)(implicit sourceInfo: SourceInfo): Bool = compop(sourceInfo, NotEqualOp, that) - def do_=== (that: UInt)(implicit sourceInfo: SourceInfo): Bool = compop(sourceInfo, EqualOp, that) - - final def unary_! () : Bool = macro SourceInfoTransform.noArg - - def do_unary_! (implicit sourceInfo: SourceInfo) : Bool = this === Bits(0) - - override def do_<< (that: Int)(implicit sourceInfo: SourceInfo): UInt = - binop(sourceInfo, UInt(this.width + that), ShiftLeftOp, that) - override def do_<< (that: BigInt)(implicit sourceInfo: SourceInfo): UInt = - this << that.toInt - override def do_<< (that: UInt)(implicit sourceInfo: SourceInfo): UInt = - binop(sourceInfo, UInt(this.width.dynamicShiftLeft(that.width)), DynamicShiftLeftOp, that) - override def do_>> (that: Int)(implicit sourceInfo: SourceInfo): UInt = - binop(sourceInfo, UInt(this.width.shiftRight(that)), ShiftRightOp, that) - override def do_>> (that: BigInt)(implicit sourceInfo: SourceInfo): UInt = - this >> that.toInt - override def do_>> (that: UInt)(implicit sourceInfo: SourceInfo): UInt = - binop(sourceInfo, UInt(this.width), DynamicShiftRightOp, that) - - final def bitSet(off: UInt, dat: Bool): UInt = macro UIntTransform.bitset - - def do_bitSet(off: UInt, dat: Bool)(implicit sourceInfo: SourceInfo): UInt = { - val bit = UInt(1, 1) << off - Mux(dat, this | bit, ~(~this | bit)) - } - - /** 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. - final def zext(): SInt = macro SourceInfoTransform.noArg - def do_zext(implicit sourceInfo: SourceInfo): SInt = - pushOp(DefPrim(sourceInfo, 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). - */ - override def do_asSInt(implicit sourceInfo: SourceInfo): SInt = - pushOp(DefPrim(sourceInfo, SInt(width), AsSIntOp, ref)) - override def do_asUInt(implicit sourceInfo: SourceInfo): 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)(implicit sourceInfo: SourceInfo): Unit = that match { - case _: SInt => this connect that - case _ => this badConnect that - } - - override private[Chisel] def fromInt(value: BigInt, width: Int): this.type = - SInt(value, width).asInstanceOf[this.type] - - final def unary_- (): SInt = macro SourceInfoTransform.noArg - final def unary_-% (): SInt = macro SourceInfoTransform.noArg - - def unary_- (implicit sourceInfo: SourceInfo): SInt = SInt(0) - this - def unary_-% (implicit sourceInfo: SourceInfo): SInt = SInt(0) -% this - - /** add (default - no growth) operator */ - override def do_+ (that: SInt)(implicit sourceInfo: SourceInfo): SInt = - this +% that - /** subtract (default - no growth) operator */ - override def do_- (that: SInt)(implicit sourceInfo: SourceInfo): SInt = - this -% that - override def do_* (that: SInt)(implicit sourceInfo: SourceInfo): SInt = - binop(sourceInfo, SInt(this.width + that.width), TimesOp, that) - override def do_/ (that: SInt)(implicit sourceInfo: SourceInfo): SInt = - binop(sourceInfo, SInt(this.width), DivideOp, that) - override def do_% (that: SInt)(implicit sourceInfo: SourceInfo): SInt = - binop(sourceInfo, SInt(this.width), RemOp, that) - - final def * (that: UInt): SInt = macro SourceInfoTransform.thatArg - def do_* (that: UInt)(implicit sourceInfo: SourceInfo): SInt = - binop(sourceInfo, SInt(this.width + that.width), TimesOp, that) - - /** add (width +1) operator */ - final def +& (that: SInt): SInt = macro SourceInfoTransform.thatArg - /** add (no growth) operator */ - final def +% (that: SInt): SInt = macro SourceInfoTransform.thatArg - /** subtract (width +1) operator */ - final def -& (that: SInt): SInt = macro SourceInfoTransform.thatArg - /** subtract (no growth) operator */ - final def -% (that: SInt): SInt = macro SourceInfoTransform.thatArg - - def do_+& (that: SInt)(implicit sourceInfo: SourceInfo): SInt = - binop(sourceInfo, SInt((this.width max that.width) + 1), AddOp, that) - def do_+% (that: SInt)(implicit sourceInfo: SourceInfo): SInt = - (this +& that).tail(1).asSInt - def do_-& (that: SInt)(implicit sourceInfo: SourceInfo): SInt = - binop(sourceInfo, SInt((this.width max that.width) + 1), SubOp, that) - def do_-% (that: SInt)(implicit sourceInfo: SourceInfo): SInt = - (this -& that).tail(1).asSInt - - final def & (that: SInt): SInt = macro SourceInfoTransform.thatArg - final def | (that: SInt): SInt = macro SourceInfoTransform.thatArg - final def ^ (that: SInt): SInt = macro SourceInfoTransform.thatArg - - def do_& (that: SInt)(implicit sourceInfo: SourceInfo): SInt = - binop(sourceInfo, UInt(this.width max that.width), BitAndOp, that).asSInt - def do_| (that: SInt)(implicit sourceInfo: SourceInfo): SInt = - binop(sourceInfo, UInt(this.width max that.width), BitOrOp, that).asSInt - def do_^ (that: SInt)(implicit sourceInfo: SourceInfo): SInt = - binop(sourceInfo, UInt(this.width max that.width), BitXorOp, that).asSInt - - /** Returns this wire bitwise-inverted. */ - def do_unary_~ (implicit sourceInfo: SourceInfo): SInt = - unop(sourceInfo, UInt(width = width), BitNotOp).asSInt - - override def do_< (that: SInt)(implicit sourceInfo: SourceInfo): Bool = compop(sourceInfo, LessOp, that) - override def do_> (that: SInt)(implicit sourceInfo: SourceInfo): Bool = compop(sourceInfo, GreaterOp, that) - override def do_<= (that: SInt)(implicit sourceInfo: SourceInfo): Bool = compop(sourceInfo, LessEqOp, that) - override def do_>= (that: SInt)(implicit sourceInfo: SourceInfo): Bool = compop(sourceInfo, GreaterEqOp, that) - - final def != (that: SInt): Bool = macro SourceInfoTransform.thatArg - final def =/= (that: SInt): Bool = macro SourceInfoTransform.thatArg - final def === (that: SInt): Bool = macro SourceInfoTransform.thatArg - - def do_!= (that: SInt)(implicit sourceInfo: SourceInfo): Bool = compop(sourceInfo, NotEqualOp, that) - def do_=/= (that: SInt)(implicit sourceInfo: SourceInfo): Bool = compop(sourceInfo, NotEqualOp, that) - def do_=== (that: SInt)(implicit sourceInfo: SourceInfo): Bool = compop(sourceInfo, EqualOp, that) - - final def abs(): UInt = macro SourceInfoTransform.noArg - - def do_abs(implicit sourceInfo: SourceInfo): UInt = Mux(this < SInt(0), (-this).asUInt, this.asUInt) - - override def do_<< (that: Int)(implicit sourceInfo: SourceInfo): SInt = - binop(sourceInfo, SInt(this.width + that), ShiftLeftOp, that) - override def do_<< (that: BigInt)(implicit sourceInfo: SourceInfo): SInt = - this << that.toInt - override def do_<< (that: UInt)(implicit sourceInfo: SourceInfo): SInt = - binop(sourceInfo, SInt(this.width.dynamicShiftLeft(that.width)), DynamicShiftLeftOp, that) - override def do_>> (that: Int)(implicit sourceInfo: SourceInfo): SInt = - binop(sourceInfo, SInt(this.width.shiftRight(that)), ShiftRightOp, that) - override def do_>> (that: BigInt)(implicit sourceInfo: SourceInfo): SInt = - this >> that.toInt - override def do_>> (that: UInt)(implicit sourceInfo: SourceInfo): SInt = - binop(sourceInfo, SInt(this.width), DynamicShiftRightOp, that) - - override def do_asUInt(implicit sourceInfo: SourceInfo): UInt = pushOp(DefPrim(sourceInfo, UInt(this.width), AsUIntOp, ref)) - override def do_asSInt(implicit sourceInfo: SourceInfo): 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, width: Int): this.type = { - require((value == 0 || value == 1) && width == 1) - Bool(value == 1).asInstanceOf[this.type] - } - - // REVIEW TODO: Why does this need to exist and have different conventions - // than Bits? - final def & (that: Bool): Bool = macro SourceInfoTransform.thatArg - final def | (that: Bool): Bool = macro SourceInfoTransform.thatArg - final def ^ (that: Bool): Bool = macro SourceInfoTransform.thatArg - - def do_& (that: Bool)(implicit sourceInfo: SourceInfo): Bool = - binop(sourceInfo, Bool(), BitAndOp, that) - def do_| (that: Bool)(implicit sourceInfo: SourceInfo): Bool = - binop(sourceInfo, Bool(), BitOrOp, that) - def do_^ (that: Bool)(implicit sourceInfo: SourceInfo): Bool = - binop(sourceInfo, Bool(), BitXorOp, that) - - /** Returns this wire bitwise-inverted. */ - override def do_unary_~ (implicit sourceInfo: SourceInfo): Bool = - unop(sourceInfo, Bool(), BitNotOp) - - /** Outputs the logical OR of two Bools. - */ - def || (that: Bool): Bool = macro SourceInfoTransform.thatArg - - def do_|| (that: Bool)(implicit sourceInfo: SourceInfo): Bool = this | that - - /** Outputs the logical AND of two Bools. - */ - def && (that: Bool): Bool = macro SourceInfoTransform.thatArg - - def do_&& (that: Bool)(implicit sourceInfo: SourceInfo): 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 = macro MuxTransform.apply[T] - - def do_apply[T <: Data](cond: Bool, con: T, alt: T)(implicit sourceInfo: SourceInfo): 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)(implicit sourceInfo: SourceInfo): 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(sourceInfo, d, MultiplexOp, cond.ref, con.ref, alt.ref)) - } - - private def doAggregateMux[T <: Data](cond: Bool, con: T, alt: T)(implicit sourceInfo: SourceInfo): 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 deleted file mode 100644 index b634f021..00000000 --- a/chiselFrontend/src/main/scala/Chisel/BlackBox.scala +++ /dev/null @@ -1,55 +0,0 @@ -// See LICENSE for license details. - -package Chisel - -import internal.Builder.pushCommand -import internal.firrtl.{ModuleIO, DefInvalid} -import internal.sourceinfo.SourceInfo - -/** 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(implicit sourceInfo: SourceInfo): this.type = _parent match { - case Some(p) => { - // Just init instance inputs - for((_,port) <- ports) pushCommand(DefInvalid(sourceInfo, 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/Data.scala b/chiselFrontend/src/main/scala/Chisel/Data.scala deleted file mode 100644 index d16843f7..00000000 --- a/chiselFrontend/src/main/scala/Chisel/Data.scala +++ /dev/null @@ -1,161 +0,0 @@ -// See LICENSE for license details. - -package Chisel - -import scala.language.experimental.macros - -import internal._ -import internal.Builder.pushCommand -import internal.firrtl._ -import internal.sourceinfo.{SourceInfo, DeprecatedSourceInfo, UnlocatableSourceInfo, WireTransform, SourceInfoTransform} - -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)(implicit sourceInfo: SourceInfo): Unit = - throwException(s"cannot connect ${this} and ${that}") - private[Chisel] def connect(that: Data)(implicit sourceInfo: SourceInfo): Unit = - pushCommand(Connect(sourceInfo, this.lref, that.ref)) - private[Chisel] def bulkConnect(that: Data)(implicit sourceInfo: SourceInfo): Unit = - pushCommand(BulkConnect(sourceInfo, 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)(implicit sourceInfo: SourceInfo): Unit = this badConnect that - - def <> (that: Data)(implicit sourceInfo: SourceInfo): 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(that: Bits): this.type = macro SourceInfoTransform.thatArg - - def do_fromBits(that: Bits)(implicit sourceInfo: SourceInfo): this.type = { - var i = 0 - val wire = Wire(this.cloneType) - val bits = - if (that.width.known && that.width.get >= wire.width.get) { - that - } else { - Wire(that.cloneTypeWidth(wire.width), init = that) - } - 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). - */ - @deprecated("Use asBits, which makes the reinterpret cast more explicit and actually returns Bits", "chisel3") - def toBits(): UInt = SeqUtils.do_asUInt(this.flatten)(DeprecatedSourceInfo) -} - -object Wire { - def apply[T <: Data](t: T): T = macro WireTransform.apply[T] - - // No source info since Scala macros don't yet support named / default arguments. - def apply[T <: Data](dummy: Int = 0, init: T): T = - do_apply(null.asInstanceOf[T], init)(UnlocatableSourceInfo) - - // No source info since Scala macros don't yet support named / default arguments. - def apply[T <: Data](t: T, init: T): T = - do_apply(t, init)(UnlocatableSourceInfo) - - def do_apply[T <: Data](t: T, init: T)(implicit sourceInfo: SourceInfo): T = { - val x = Reg.makeType(t, null.asInstanceOf[T], init) - pushCommand(DefWire(sourceInfo, x)) - pushCommand(DefInvalid(sourceInfo, 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)(implicit sourceInfo: SourceInfo): 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 deleted file mode 100644 index e34d5499..00000000 --- a/chiselFrontend/src/main/scala/Chisel/Mem.scala +++ /dev/null @@ -1,134 +0,0 @@ -// See LICENSE for license details. - -package Chisel - -import scala.language.experimental.macros - -import internal._ -import internal.Builder.pushCommand -import internal.firrtl._ -import internal.sourceinfo.{SourceInfo, DeprecatedSourceInfo, UnlocatableSourceInfo, MemTransform} - -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] = do_apply(size, t)(UnlocatableSourceInfo) - - /** 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] = macro MemTransform.apply[T] - - def do_apply[T <: Data](size: Int, t: T)(implicit sourceInfo: SourceInfo): Mem[T] = { - val mt = t.cloneType - val mem = new Mem(mt, size) - pushCommand(DefMemory(sourceInfo, 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(UnlocatableSourceInfo, 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(UnlocatableSourceInfo, 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 = { - implicit val sourceInfo = UnlocatableSourceInfo - makePort(UnlocatableSourceInfo, 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: Seq[Bool]) (implicit evidence: T <:< Vec[_]): Unit = { - implicit val sourceInfo = UnlocatableSourceInfo - val accessor = makePort(sourceInfo, 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(sourceInfo: SourceInfo, idx: UInt, dir: MemPortDirection): T = - pushCommand(DefMemPort(sourceInfo, - 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] = do_apply(size, t)(DeprecatedSourceInfo) - - /** 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] = macro MemTransform.apply[T] - - def do_apply[T <: Data](size: Int, t: T)(implicit sourceInfo: SourceInfo): SeqMem[T] = { - val mt = t.cloneType - val mem = new SeqMem(mt, size) - pushCommand(DefSeqMemory(sourceInfo, 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 = { - implicit val sourceInfo = UnlocatableSourceInfo - 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 deleted file mode 100644 index e2101538..00000000 --- a/chiselFrontend/src/main/scala/Chisel/Module.scala +++ /dev/null @@ -1,119 +0,0 @@ -// See LICENSE for license details. - -package Chisel - -import scala.collection.mutable.{ArrayBuffer, HashSet} -import scala.language.experimental.macros - -import internal._ -import internal.Builder.pushCommand -import internal.Builder.dynamicContext -import internal.firrtl._ -import internal.sourceinfo.{SourceInfo, InstTransform, UnlocatableSourceInfo} - -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 = macro InstTransform.apply[T] - - def do_apply[T <: Module](bc: => T)(implicit sourceInfo: SourceInfo): T = { - // Don't generate source info referencing parents inside a module, sincce this interferes with - // module de-duplication in FIRRTL emission. - val childSourceInfo = UnlocatableSourceInfo - - val parent = dynamicContext.currentModule - val m = bc.setRefs() - m._commands.prepend(DefInvalid(childSourceInfo, m.io.ref)) // init module outputs - dynamicContext.currentModule = parent - val ports = m.computePorts - Builder.components += Component(m, m.name, ports, m._commands) - pushCommand(DefInstance(sourceInfo, m, ports)) - m.setupInParent(childSourceInfo) - } -} - -/** 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(Option(_clock), None) - def this(_reset: Bool) = this(None, Option(_reset)) - def this(_clock: Clock, _reset: Bool) = this(Option(_clock), Option(_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(implicit sourceInfo: SourceInfo): this.type = { - _parent match { - case Some(p) => { - pushCommand(DefInvalid(sourceInfo, 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 _ => - } - - // For Module instances we haven't named, suggest the name of the Module - _ids foreach { - case m: Module => m.suggestName(m.name) - 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/Printf.scala b/chiselFrontend/src/main/scala/Chisel/Printf.scala deleted file mode 100644 index f068f637..00000000 --- a/chiselFrontend/src/main/scala/Chisel/Printf.scala +++ /dev/null @@ -1,36 +0,0 @@ -// See LICENSE for license details. - -package Chisel - -import scala.language.experimental.macros - -import internal._ -import internal.Builder.pushCommand -import internal.firrtl._ -import internal.sourceinfo.SourceInfo - -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*)(implicit sourceInfo: SourceInfo) { - when (!(Builder.dynamicContext.currentModule.get.reset)) { - printfWithoutReset(fmt, data:_*) - } - } - - private[Chisel] def printfWithoutReset(fmt: String, data: Bits*)(implicit sourceInfo: SourceInfo) { - val clock = Builder.dynamicContext.currentModule.get.clock - pushCommand(Printf(sourceInfo, Node(clock), fmt, data.map((d: Bits) => d.ref))) - } -} diff --git a/chiselFrontend/src/main/scala/Chisel/Reg.scala b/chiselFrontend/src/main/scala/Chisel/Reg.scala deleted file mode 100644 index c8faa5c9..00000000 --- a/chiselFrontend/src/main/scala/Chisel/Reg.scala +++ /dev/null @@ -1,71 +0,0 @@ -// See LICENSE for license details. - -package Chisel - -import internal._ -import internal.Builder.pushCommand -import internal.firrtl._ -import internal.sourceinfo.{SourceInfo, UnlocatableSourceInfo} - -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 = - // Scala macros can't (yet) handle named or default arguments. - do_apply(t, next, init)(UnlocatableSourceInfo) - - /** 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]) - - def do_apply[T <: Data](t: T, next: T, init: T)(implicit sourceInfo: SourceInfo): 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(sourceInfo, x, clock)) - } else { - pushCommand(DefRegInit(sourceInfo, x, clock, Node(x._parent.get.reset), init.ref)) - } - if (next != null) { - x := next - } - x - } -} diff --git a/chiselFrontend/src/main/scala/Chisel/SeqUtils.scala b/chiselFrontend/src/main/scala/Chisel/SeqUtils.scala deleted file mode 100644 index 9a15fd5f..00000000 --- a/chiselFrontend/src/main/scala/Chisel/SeqUtils.scala +++ /dev/null @@ -1,59 +0,0 @@ -// See LICENSE for license details. - -package Chisel - -import scala.language.experimental.macros - -import internal.sourceinfo.{SourceInfo, SourceInfoTransform} - -private[Chisel] object SeqUtils { - /** Equivalent to Cat(r(n-1), ..., r(0)) */ - def asUInt[T <: Bits](in: Seq[T]): UInt = macro SourceInfoTransform.inArg - - def do_asUInt[T <: Bits](in: Seq[T])(implicit sourceInfo: SourceInfo): 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 = macro SourceInfoTransform.inArg - - def do_count(in: Seq[Bool])(implicit sourceInfo: SourceInfo): 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 <: Data](in: Seq[(Bool, T)]): T = macro SourceInfoTransform.inArg - - def do_priorityMux[T <: Data](in: Seq[(Bool, T)])(implicit sourceInfo: SourceInfo): 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 = macro SourceInfoTransform.inArg - - def do_oneHotMux[T <: Data](in: Iterable[(Bool, T)])(implicit sourceInfo: SourceInfo): 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 deleted file mode 100644 index 90b3d1a5..00000000 --- a/chiselFrontend/src/main/scala/Chisel/When.scala +++ /dev/null @@ -1,59 +0,0 @@ -// See LICENSE for license details. - -package Chisel - -import scala.language.experimental.macros - -import internal._ -import internal.Builder.pushCommand -import internal.firrtl._ -import internal.sourceinfo.{SourceInfo} - -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)(implicit sourceInfo: SourceInfo): WhenContext = { - new WhenContext(sourceInfo, 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. - */ -final class WhenContext(sourceInfo: SourceInfo, 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)(implicit sourceInfo: SourceInfo): WhenContext = { - new WhenContext(sourceInfo, 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)(implicit sourceInfo: SourceInfo): Unit = - new WhenContext(sourceInfo, prevCond, null, block) - - pushCommand(WhenBegin(sourceInfo, cond.ref)) - block - pushCommand(WhenEnd(sourceInfo)) -} diff --git a/chiselFrontend/src/main/scala/Chisel/internal/Builder.scala b/chiselFrontend/src/main/scala/Chisel/internal/Builder.scala deleted file mode 100644 index d0e28b7c..00000000 --- a/chiselFrontend/src/main/scala/Chisel/internal/Builder.scala +++ /dev/null @@ -1,123 +0,0 @@ -// 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 getOrElse (new DynamicContext) - 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 deleted file mode 100644 index 6c4c0880..00000000 --- a/chiselFrontend/src/main/scala/Chisel/internal/Error.scala +++ /dev/null @@ -1,91 +0,0 @@ -// 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/SourceInfo.scala b/chiselFrontend/src/main/scala/Chisel/internal/SourceInfo.scala deleted file mode 100644 index 66bfc7a4..00000000 --- a/chiselFrontend/src/main/scala/Chisel/internal/SourceInfo.scala +++ /dev/null @@ -1,51 +0,0 @@ -// See LICENSE for license details. - -// This file contains macros for adding source locators at the point of invocation. -// -// This is not part of coreMacros to disallow this macro from being implicitly invoked in Chisel -// frontend (and generating source locators in Chisel core), which is almost certainly a bug. -// -// Note: While these functions and definitions are not private (macros can't be -// private), these are NOT meant to be part of the public API (yet) and no -// forward compatibility guarantees are made. -// A future revision may stabilize the source locator API to allow library -// writers to append source locator information at the point of a library -// function invocation. - -package Chisel.internal.sourceinfo - -import scala.language.experimental.macros -import scala.reflect.macros.blackbox.Context - -/** Abstract base class for generalized source information. - */ -sealed trait SourceInfo - -sealed trait NoSourceInfo extends SourceInfo - -/** For when source info can't be generated because of a technical limitation, like for Reg because - * Scala macros don't support named or default arguments. - */ -case object UnlocatableSourceInfo extends NoSourceInfo - -/** For when source info isn't generated because the function is deprecated and we're lazy. - */ -case object DeprecatedSourceInfo extends NoSourceInfo - -/** For FIRRTL lines from a Scala source line. - */ -case class SourceLine(filename: String, line: Int, col: Int) extends SourceInfo - -/** Provides a macro that returns the source information at the invocation point. - */ -object SourceInfoMacro { - def generate_source_info(c: Context): c.Tree = { - import c.universe._ - val p = c.enclosingPosition - q"_root_.Chisel.internal.sourceinfo.SourceLine(${p.source.file.name}, ${p.line}, ${p.column})" - } -} - -object SourceInfo { - implicit def materialize: SourceInfo = macro SourceInfoMacro.generate_source_info -} diff --git a/chiselFrontend/src/main/scala/Chisel/internal/firrtl/IR.scala b/chiselFrontend/src/main/scala/Chisel/internal/firrtl/IR.scala deleted file mode 100644 index 62784cee..00000000 --- a/chiselFrontend/src/main/scala/Chisel/internal/firrtl/IR.scala +++ /dev/null @@ -1,188 +0,0 @@ -// See LICENSE for license details. - -package Chisel.internal.firrtl -import Chisel._ -import Chisel.internal._ -import Chisel.internal.sourceinfo.{SourceInfo, NoSourceInfo} - -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 { - def sourceInfo: SourceInfo -} -abstract class Definition extends Command { - def id: HasId - def name: String = id.getRef.name -} -case class DefPrim[T <: Data](sourceInfo: SourceInfo, id: T, op: PrimOp, args: Arg*) extends Definition -case class DefInvalid(sourceInfo: SourceInfo, arg: Arg) extends Command -case class DefWire(sourceInfo: SourceInfo, id: Data) extends Definition -case class DefReg(sourceInfo: SourceInfo, id: Data, clock: Arg) extends Definition -case class DefRegInit(sourceInfo: SourceInfo, id: Data, clock: Arg, reset: Arg, init: Arg) extends Definition -case class DefMemory(sourceInfo: SourceInfo, id: HasId, t: Data, size: Int) extends Definition -case class DefSeqMemory(sourceInfo: SourceInfo, id: HasId, t: Data, size: Int) extends Definition -case class DefMemPort[T <: Data](sourceInfo: SourceInfo, id: T, source: Node, dir: MemPortDirection, index: Arg, clock: Arg) extends Definition -case class DefInstance(sourceInfo: SourceInfo, id: Module, ports: Seq[Port]) extends Definition -case class WhenBegin(sourceInfo: SourceInfo, pred: Arg) extends Command -case class WhenEnd(sourceInfo: SourceInfo) extends Command -case class Connect(sourceInfo: SourceInfo, loc: Node, exp: Arg) extends Command -case class BulkConnect(sourceInfo: SourceInfo, loc1: Node, loc2: Node) extends Command -case class ConnectInit(sourceInfo: SourceInfo, loc: Node, exp: Arg) extends Command -case class Stop(sourceInfo: SourceInfo, 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(sourceInfo: SourceInfo, 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]) diff --git a/chiselFrontend/src/main/scala/chisel3/core/Aggregate.scala b/chiselFrontend/src/main/scala/chisel3/core/Aggregate.scala new file mode 100644 index 00000000..1eef5d69 --- /dev/null +++ b/chiselFrontend/src/main/scala/chisel3/core/Aggregate.scala @@ -0,0 +1,377 @@ +// See LICENSE for license details. + +package Chisel + +import scala.collection.immutable.ListMap +import scala.collection.mutable.{ArrayBuffer, HashSet, LinkedHashMap} +import scala.language.experimental.macros + +import internal._ +import internal.Builder.pushCommand +import internal.firrtl._ +import internal.sourceinfo.{SourceInfo, DeprecatedSourceInfo, VecTransform, SourceInfoTransform} + +/** 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] = macro VecTransform.apply_elts + + def do_apply[T <: Data](elts: Seq[T])(implicit sourceInfo: SourceInfo): 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] = macro VecTransform.apply_elt0 + + def do_apply[T <: Data](elt0: T, elts: T*)(implicit sourceInfo: SourceInfo): 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] = macro VecTransform.tabulate + + def do_tabulate[T <: Data](n: Int)(gen: (Int) => T)(implicit sourceInfo: SourceInfo): 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] = macro VecTransform.fill + + def do_fill[T <: Data](n: Int)(gen: => T)(implicit sourceInfo: SourceInfo): 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)(implicit sourceInfo: SourceInfo): 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])(implicit sourceInfo: SourceInfo): Unit = this := that + + // TODO: eliminate once assign(Seq) isn't ambiguous with assign(Data) since Vec extends Seq and Data + def <> (that: Vec[T])(implicit sourceInfo: SourceInfo): Unit = this := that.asInstanceOf[Data] + + override def := (that: Data)(implicit sourceInfo: SourceInfo): 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])(implicit sourceInfo: SourceInfo): 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])(implicit sourceInfo: SourceInfo): 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)(DeprecatedSourceInfo) + + 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] with HasId { + def apply(idx: UInt): T + + // IndexedSeq has its own hashCode/equals that we must not use + override def hashCode: Int = super[HasId].hashCode + override def equals(that: Any): Boolean = super[HasId].equals(that) + + @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 = macro SourceInfoTransform.pArg + + def do_forall(p: T => Bool)(implicit sourceInfo: SourceInfo): Bool = + (this map p).fold(Bool(true))(_ && _) + + /** Outputs true if p outputs true for at least one element. + */ + def exists(p: T => Bool): Bool = macro SourceInfoTransform.pArg + + def do_exists(p: T => Bool)(implicit sourceInfo: SourceInfo): 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 ev: T <:< UInt): Bool = macro VecTransform.contains + + def do_contains(x: T)(implicit sourceInfo: SourceInfo, ev: T <:< UInt): Bool = + this.exists(_ === x) + + /** Outputs the number of elements for which p is true. + */ + def count(p: T => Bool): UInt = macro SourceInfoTransform.pArg + + def do_count(p: T => Bool)(implicit sourceInfo: SourceInfo): 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 = macro SourceInfoTransform.pArg + + def do_indexWhere(p: T => Bool)(implicit sourceInfo: SourceInfo): UInt = + SeqUtils.priorityMux(indexWhereHelper(p)) + + /** Outputs the index of the last element for which p outputs true. + */ + def lastIndexWhere(p: T => Bool): UInt = macro SourceInfoTransform.pArg + + def do_lastIndexWhere(p: T => Bool)(implicit sourceInfo: SourceInfo): 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 = macro SourceInfoTransform.pArg + + def do_onlyIndexWhere(p: T => Bool)(implicit sourceInfo: SourceInfo): 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)(implicit sourceInfo: SourceInfo): 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)(implicit sourceInfo: SourceInfo): 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/chisel3/core/Assert.scala b/chiselFrontend/src/main/scala/chisel3/core/Assert.scala new file mode 100644 index 00000000..c086f014 --- /dev/null +++ b/chiselFrontend/src/main/scala/chisel3/core/Assert.scala @@ -0,0 +1,73 @@ +// See LICENSE for license details. + +package Chisel + +import scala.reflect.macros.blackbox.Context +import scala.language.experimental.macros + +import internal._ +import internal.Builder.pushCommand +import internal.firrtl._ +import internal.sourceinfo.SourceInfo + +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 + */ + // Macros currently can't take default arguments, so we need two functions to emulate defaults. + def apply(cond: Bool, message: String)(implicit sourceInfo: SourceInfo): Unit = macro apply_impl_msg + def apply(cond: Bool)(implicit sourceInfo: SourceInfo): Unit = macro apply_impl + + def apply_impl_msg(c: Context)(cond: c.Tree, message: c.Tree)(sourceInfo: 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))($sourceInfo)" + } + + def apply_impl(c: Context)(cond: c.Tree)(sourceInfo: 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)($sourceInfo)" + } + + def apply_impl_do(cond: Bool, line: String, message: Option[String])(implicit sourceInfo: SourceInfo) { + 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(sourceInfo, 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, "") + } +} diff --git a/chiselFrontend/src/main/scala/chisel3/core/BiConnect.scala b/chiselFrontend/src/main/scala/chisel3/core/BiConnect.scala new file mode 100644 index 00000000..42d85bfb --- /dev/null +++ b/chiselFrontend/src/main/scala/chisel3/core/BiConnect.scala @@ -0,0 +1,190 @@ +package Chisel + +import internal.Builder.pushCommand +import internal.firrtl.Connect +import scala.language.experimental.macros +import internal.sourceinfo.{SourceInfo, DeprecatedSourceInfo, UnlocatableSourceInfo, WireTransform, SourceInfoTransform} + +/** +* BiConnect.connect executes a bidirectional connection element-wise. +* +* Note that the arguments are left and right (not source and sink) so the +* intent is for the operation to be commutative. +* +* The connect operation will recurse down the left Data (with the right Data). +* An exception will be thrown if a movement through the left cannot be matched +* in the right (or if the right side has extra fields). +* +* See elemConnect for details on how the root connections are issued. +* +*/ + +object BiConnect { + // These are all the possible exceptions that can be thrown. + case class BiConnectException(message: String) extends Exception(message) + // These are from element-level connection + def BothDriversException = + BiConnectException(": Both Left and Right are drivers") + def NeitherDriverException = + BiConnectException(": Neither Left nor Right is a driver") + def UnknownDriverException = + BiConnectException(": Locally unclear whether Left or Right (both internal)") + def UnknownRelationException = + BiConnectException(": Left or Right unavailable to current module.") + // These are when recursing down aggregate types + def MismatchedVecException = + BiConnectException(": Left and Right are different length Vecs.") + def MissingLeftFieldException(field: String) = + BiConnectException(s".$field: Left Bundle missing field ($field).") + def MissingRightFieldException(field: String) = + BiConnectException(s": Right Bundle missing field ($field).") + def MismatchedException(left: String, right: String) = + BiConnectException(s": Left ($left) and Right ($right) have different types.") + + /** This function is what recursively tries to connect a left and right together + * + * There is some cleverness in the use of internal try-catch to catch exceptions + * during the recursive decent and then rethrow them with extra information added. + * This gives the user a 'path' to where in the connections things went wrong. + */ + def connect(sourceInfo: SourceInfo, left: Data, right: Data, context_mod: Module): Unit = + (left, right) match { + // Handle element case (root case) + case (left_e: Element, right_e: Element) => { + elemConnect(sourceInfo, left_e, right_e, context_mod) + // TODO(twigg): Verify the element-level classes are connectable + } + // Handle Vec case + case (left_v: Vec[Data @unchecked], right_v: Vec[Data @unchecked]) => { + if(left_v.length != right_v.length) { throw MismatchedVecException } + for(idx <- 0 until left_v.length) { + try { + connect(sourceInfo, left_v(idx), right_v(idx), context_mod) + } catch { + case BiConnectException(message) => throw BiConnectException(s"($idx)$message") + } + } + } + // Handle Bundle case + case (left_b: Bundle, right_b: Bundle) => { + // Verify right has no extra fields that left doesn't have + for((field, right_sub) <- right_b.elements) { + if(!left_b.elements.isDefinedAt(field)) throw MissingLeftFieldException(field) + } + // For each field in left, descend with right + for((field, left_sub) <- left_b.elements) { + try { + right_b.elements.get(field) match { + case Some(right_sub) => connect(sourceInfo, left_sub, right_sub, context_mod) + case None => throw MissingRightFieldException(field) + } + } catch { + case BiConnectException(message) => throw BiConnectException(s".$field$message") + } + } + } + // Left and right are different subtypes of Data so fail + case (left, right) => throw MismatchedException(left.toString, right.toString) + } + + // These functions (finally) issue the connection operation + // Issue with right as sink, left as source + private def issueConnectL2R(left: Element, right: Element)(implicit sourceInfo: SourceInfo): Unit = { + pushCommand(Connect(sourceInfo, right.lref, left.ref)) + } + // Issue with left as sink, right as source + private def issueConnectR2L(left: Element, right: Element)(implicit sourceInfo: SourceInfo): Unit = { + pushCommand(Connect(sourceInfo, left.lref, right.ref)) + } + + // This function checks if element-level connection operation allowed. + // Then it either issues it or throws the appropriate exception. + def elemConnect(implicit sourceInfo: SourceInfo, left: Element, right: Element, context_mod: Module): Unit = { + import Direction.{Input, Output} // Using extensively so import these + // If left or right have no location, assume in context module + // This can occur if one of them is a literal, unbound will error previously + val left_mod: Module = left.binding.location.getOrElse(context_mod) + val right_mod: Module = right.binding.location.getOrElse(context_mod) + + val left_direction: Option[Direction] = left.binding.direction + val right_direction: Option[Direction] = right.binding.direction + // None means internal + + // CASE: Context is same module as left node and right node is in a child module + if( (left_mod == context_mod) && + (right_mod._parent.map(_ == context_mod).getOrElse(false)) ) { + // Thus, right node better be a port node and thus have a direction hint + (left_direction, right_direction) match { + // CURRENT MOD CHILD MOD + case (Some(Input), Some(Input)) => issueConnectL2R(left, right) + case (None, Some(Input)) => issueConnectL2R(left, right) + + case (Some(Output), Some(Output)) => issueConnectR2L(left, right) + case (None, Some(Output)) => issueConnectR2L(left, right) + + case (Some(Input), Some(Output)) => throw BothDriversException + case (Some(Output), Some(Input)) => throw NeitherDriverException + case (_, None) => throw UnknownRelationException + } + } + + // CASE: Context is same module as right node and left node is in child module + else if( (right_mod == context_mod) && + (left_mod._parent.map(_ == context_mod).getOrElse(false)) ) { + // Thus, left node better be a port node and thus have a direction hint + (left_direction, right_direction) match { + // CHILD MOD CURRENT MOD + case (Some(Input), Some(Input)) => issueConnectR2L(left, right) + case (Some(Input), None) => issueConnectR2L(left, right) + + case (Some(Output), Some(Output)) => issueConnectL2R(left, right) + case (Some(Output), None) => issueConnectL2R(left, right) + + case (Some(Input), Some(Output)) => throw NeitherDriverException + case (Some(Output), Some(Input)) => throw BothDriversException + case (None, _) => throw UnknownRelationException + } + } + + // CASE: Context is same module that both left node and right node are in + else if( (context_mod == left_mod) && (context_mod == right_mod) ) { + (left_direction, right_direction) match { + // CURRENT MOD CURRENT MOD + case (Some(Input), Some(Output)) => issueConnectL2R(left, right) + case (Some(Input), None) => issueConnectL2R(left, right) + case (None, Some(Output)) => issueConnectL2R(left, right) + + case (Some(Output), Some(Input)) => issueConnectR2L(left, right) + case (Some(Output), None) => issueConnectR2L(left, right) + case (None, Some(Input)) => issueConnectR2L(left, right) + + case (Some(Input), Some(Input)) => throw BothDriversException + case (Some(Output), Some(Output)) => throw NeitherDriverException + case (None, None) => throw UnknownDriverException + } + } + + // CASE: Context is the parent module of both the module containing left node + // and the module containing right node + // Note: This includes case when left and right in same module but in parent + else if( (left_mod._parent.map(_ == context_mod).getOrElse(false)) && + (right_mod._parent.map(_ == context_mod).getOrElse(false)) + ) { + // Thus both nodes must be ports and have a direction hint + (left_direction, right_direction) match { + // CHILD MOD CHILD MOD + case (Some(Input), Some(Output)) => issueConnectR2L(left, right) + case (Some(Output), Some(Input)) => issueConnectL2R(left, right) + + case (Some(Input), Some(Input)) => throw NeitherDriverException + case (Some(Output), Some(Output)) => throw BothDriversException + case (_, None) => throw UnknownRelationException + case (None, _) => throw UnknownRelationException + } + } + + // Not quite sure where left and right are compared to current module + // so just error out + else throw UnknownRelationException + } +} diff --git a/chiselFrontend/src/main/scala/chisel3/core/Binder.scala b/chiselFrontend/src/main/scala/chisel3/core/Binder.scala new file mode 100644 index 00000000..ca074527 --- /dev/null +++ b/chiselFrontend/src/main/scala/chisel3/core/Binder.scala @@ -0,0 +1,64 @@ +package Chisel + +/** +* A Binder is a function from UnboundBinding to some Binding. +* +* These are used exclusively by Binding.bind and sealed in order to keep +* all of them in one place. There are two flavors of Binders: +* Non-terminal (returns another UnboundBinding): These are used to reformat an +* UnboundBinding (like setting direction) before it is terminally bound. +* Terminal (returns any other Binding): Due to the nature of Bindings, once a +* Data is bound to anything but an UnboundBinding, it is forever locked to +* being that type (as it now represents something in the hardware graph). +* +* Note that some Binders require extra arguments to be constructed, like the +* enclosing Module. +*/ + +sealed trait Binder[Out <: Binding] extends Function1[UnboundBinding, Out]{ + def apply(in: UnboundBinding): Out +} + +// THE NON-TERMINAL BINDERS +// These 'rebind' to another unbound node of different direction! +case object InputBinder extends Binder[UnboundBinding] { + def apply(in: UnboundBinding) = UnboundBinding(Some(Direction.Input)) +} +case object OutputBinder extends Binder[UnboundBinding] { + def apply(in: UnboundBinding) = UnboundBinding(Some(Direction.Output)) +} +case object FlippedBinder extends Binder[UnboundBinding] { + def apply(in: UnboundBinding) = UnboundBinding(in.direction.map(_.flip)) + // TODO(twigg): flipping a None should probably be a warning/error +} +// The need for this should be transient. +case object NoDirectionBinder extends Binder[UnboundBinding] { + def apply(in: UnboundBinding) = UnboundBinding(None) +} + +// THE TERMINAL BINDERS +case object LitBinder extends Binder[LitBinding] { + def apply(in: UnboundBinding) = LitBinding() +} + +case class MemoryPortBinder(enclosure: Module) extends Binder[MemoryPortBinding] { + def apply(in: UnboundBinding) = MemoryPortBinding(enclosure) +} + +case class OpBinder(enclosure: Module) extends Binder[OpBinding] { + def apply(in: UnboundBinding) = OpBinding(enclosure) +} + +// Notice how PortBinder uses the direction of the UnboundNode +case class PortBinder(enclosure: Module) extends Binder[PortBinding] { + def apply(in: UnboundBinding) = PortBinding(enclosure, in.direction) +} + +case class RegBinder(enclosure: Module) extends Binder[RegBinding] { + def apply(in: UnboundBinding) = RegBinding(enclosure) +} + +case class WireBinder(enclosure: Module) extends Binder[WireBinding] { + def apply(in: UnboundBinding) = WireBinding(enclosure) +} + diff --git a/chiselFrontend/src/main/scala/chisel3/core/Binding.scala b/chiselFrontend/src/main/scala/chisel3/core/Binding.scala new file mode 100644 index 00000000..949ac9cd --- /dev/null +++ b/chiselFrontend/src/main/scala/chisel3/core/Binding.scala @@ -0,0 +1,179 @@ +package Chisel + +/** + * The purpose of a Binding is to indicate what type of hardware 'entity' a + * specific Data's leaf Elements is actually bound to. All Data starts as being + * Unbound (and the whole point of cloneType is to return an unbound version). + * Then, specific API calls take a Data, and return a bound version (either by + * binding the original model or cloneType then binding the clone). For example, + * Reg[T<:Data](...) returns a T bound to RegBinding. + * + * It is considered invariant that all Elements of a single Data are bound to + * the same concrete type of Binding. + * + * These bindings can be checked (e.g. checkSynthesizable) to make sure certain + * operations are valid. For example, arithemetic operations or connections can + * only be executed between synthesizable nodes. These checks are to avoid + * undefined reference errors. + * + * Bindings can carry information about the particular element in the graph it + * represents like: + * - For ports (and unbound), the 'direction' + * - For (relevant) synthesizable nodes, the enclosing Module + * + * TODO(twigg): Enrich the bindings to carry more information like the hosting + * module (when applicable), direction (when applicable), literal info (when + * applicable). Can ensure applicable data only stored on relevant nodes. e.g. + * literal info on LitBinding, direction info on UnboundBinding and PortBinding, + * etc. + * + * TODO(twigg): Currently, bindings only apply at the Element level and an + * Aggregate is considered bound via its elements. May be appropriate to allow + * Aggregates to be bound along with the Elements. However, certain literal and + * port direction information doesn't quite make sense in aggregates. This would + * elegantly handle the empty Vec or Bundle problem though. + * + * TODO(twigg): Binding is currently done via allElements. It may be more + * elegant if this was instead done as a more explicit tree walk as that allows + * for better errors. + */ + +object Binding { + // Two bindings are 'compatible' if they are the same type. + // Check currently kind of weird: just ensures same class + private def compatible(a: Binding, b: Binding): Boolean = a.getClass == b.getClass + private def compatible(nodes: Seq[Binding]): Boolean = + if(nodes.size > 1) + (for((a,b) <- nodes zip nodes.tail) yield compatible(a,b)) + .fold(true)(_&&_) + else true + + case class BindingException(message: String) extends Exception(message) + def AlreadyBoundException(binding: String) = BindingException(s": Already bound to $binding") + def NotSynthesizableException = BindingException(s": Not bound to synthesizable node, currently only Type description") + + // This recursively walks down the Data tree to look at all the leaf 'Element's + // Will build up an error string in case something goes wrong + // TODO(twigg): Make member function of Data. + // Allows oddities like sample_element to be better hidden + private def walkToBinding(target: Data, checker: Element=>Unit): Unit = target match { + case (element: Element) => checker(element) + case (vec: Vec[Data @unchecked]) => { + try walkToBinding(vec.sample_element, checker) + catch { + case BindingException(message) => throw BindingException(s"(*)$message") + } + for(idx <- 0 until vec.length) { + try walkToBinding(vec(idx), checker) + catch { + case BindingException(message) => throw BindingException(s"($idx)$message") + } + } + } + case (bundle: Bundle) => { + for((field, subelem) <- bundle.elements) { + try walkToBinding(subelem, checker) + catch { + case BindingException(message) => throw BindingException(s".$field$message") + } + } + } + } + + // Use walkToBinding to actually rebind the node type + def bind[T<:Data](target: T, binder: Binder[_<:Binding], error_prelude: String): target.type = { + try walkToBinding( + target, + element => element.binding match { + case unbound @ UnboundBinding(_) => { + element.binding = binder(unbound) + } + case binding => throw AlreadyBoundException(binding.toString) + } + ) + catch { + case BindingException(message) => throw BindingException(s"$error_prelude$message") + } + target + } + + // Excepts if any root element is already bound + def checkUnbound(target: Data, error_prelude: String): Unit = { + try walkToBinding( + target, + element => element.binding match { + case unbound @ UnboundBinding(_) => {} + case binding => throw AlreadyBoundException(binding.toString) + } + ) + catch { + case BindingException(message) => throw BindingException(s"$error_prelude$message") + } + } + + // Excepts if any root element is unbound and thus not on the hardware graph + def checkSynthesizable(target: Data, error_prelude: String): Unit = + try walkToBinding( + target, + element => element.binding match { + case SynthesizableBinding() => {} // OK + case binding => throw NotSynthesizableException + } + ) + catch { + case BindingException(message) => throw BindingException(s"$error_prelude$message") + } +} + +// Location refers to 'where' in the Module hierarchy this lives +sealed trait Binding { + def location: Option[Module] + def direction: Option[Direction] +} + +// Constrained-ness refers to whether 'bound by Module boundaries' +// An unconstrained binding, like a literal, can be read by everyone +sealed trait UnconstrainedBinding extends Binding { + def location = None +} +// A constrained binding can only be read/written by specific modules +// Location will track where this Module is +sealed trait ConstrainedBinding extends Binding { + def enclosure: Module + def location = Some(enclosure) +} + +// An undirectioned binding means the element represents an internal node +// with no meaningful concept of a direction +sealed trait UndirectionedBinding extends Binding { def direction = None } + +// This is the default binding, represents data not yet positioned in the graph +case class UnboundBinding(direction: Option[Direction]) + extends Binding with UnconstrainedBinding + + +// A synthesizable binding is 'bound into' the hardware graph +object SynthesizableBinding { + def unapply(target: Binding): Boolean = target.isInstanceOf[SynthesizableBinding] + // Type check OK because Binding and SynthesizableBinding is sealed +} +sealed trait SynthesizableBinding extends Binding +case class LitBinding() // will eventually have literal info + extends SynthesizableBinding with UnconstrainedBinding with UndirectionedBinding + +case class MemoryPortBinding(enclosure: Module) + extends SynthesizableBinding with ConstrainedBinding with UndirectionedBinding + +// TODO(twigg): Ops between unenclosed nodes can also be unenclosed +// However, Chisel currently binds all op results to a module +case class OpBinding(enclosure: Module) + extends SynthesizableBinding with ConstrainedBinding with UndirectionedBinding + +case class PortBinding(enclosure: Module, direction: Option[Direction]) + extends SynthesizableBinding with ConstrainedBinding + +case class RegBinding(enclosure: Module) + extends SynthesizableBinding with ConstrainedBinding with UndirectionedBinding + +case class WireBinding(enclosure: Module) + extends SynthesizableBinding with ConstrainedBinding with UndirectionedBinding diff --git a/chiselFrontend/src/main/scala/chisel3/core/Bits.scala b/chiselFrontend/src/main/scala/chisel3/core/Bits.scala new file mode 100644 index 00000000..bc8cc8e2 --- /dev/null +++ b/chiselFrontend/src/main/scala/chisel3/core/Bits.scala @@ -0,0 +1,756 @@ +// See LICENSE for license details. + +package Chisel + +import scala.language.experimental.macros + +import internal._ +import internal.Builder.pushOp +import internal.firrtl._ +import internal.sourceinfo.{SourceInfo, DeprecatedSourceInfo, SourceInfoTransform, SourceInfoWhiteboxTransform, + UIntTransform, MuxTransform} +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, w: Int): this.type + + private[Chisel] def flatten: IndexedSeq[Bits] = IndexedSeq(this) + + def cloneType: this.type = cloneTypeWidth(width) + + override def <> (that: Data)(implicit sourceInfo: SourceInfo): Unit = this := that + + final def tail(n: Int): UInt = macro SourceInfoTransform.nArg + final def head(n: Int): UInt = macro SourceInfoTransform.nArg + + def do_tail(n: Int)(implicit sourceInfo: SourceInfo): 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(sourceInfo, UInt(width = w), TailOp, n) + } + + + def do_head(n: Int)(implicit sourceInfo: SourceInfo): UInt = { + width match { + case KnownWidth(x) => require(x >= n, s"Can't head($n) for width $x < $n") + case UnknownWidth() => + } + binop(sourceInfo, UInt(width = n), HeadOp, n) + } + + /** Returns the specified bit on this wire as a [[Bool]], statically + * addressed. + */ + final def apply(x: BigInt): Bool = macro SourceInfoTransform.xArg + + final def do_apply(x: BigInt)(implicit sourceInfo: SourceInfo): 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(sourceInfo, 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 = macro SourceInfoTransform.xArg + + final def do_apply(x: Int)(implicit sourceInfo: SourceInfo): Bool = apply(BigInt(x)) + + /** Returns the specified bit on this wire as a [[Bool]], dynamically + * addressed. + */ + final def apply(x: UInt): Bool = macro SourceInfoTransform.xArg + + final def do_apply(x: UInt)(implicit sourceInfo: SourceInfo): 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 = macro SourceInfoTransform.xyArg + + final def do_apply(x: Int, y: Int)(implicit sourceInfo: SourceInfo): 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(sourceInfo, 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 = macro SourceInfoTransform.xyArg + + final def do_apply(x: BigInt, y: BigInt)(implicit sourceInfo: SourceInfo): UInt = + apply(x.toInt, y.toInt) + + private[Chisel] def unop[T <: Data](sourceInfo: SourceInfo, dest: T, op: PrimOp): T = + pushOp(DefPrim(sourceInfo, dest, op, this.ref)) + private[Chisel] def binop[T <: Data](sourceInfo: SourceInfo, dest: T, op: PrimOp, other: BigInt): T = + pushOp(DefPrim(sourceInfo, dest, op, this.ref, ILit(other))) + private[Chisel] def binop[T <: Data](sourceInfo: SourceInfo, dest: T, op: PrimOp, other: Bits): T = + pushOp(DefPrim(sourceInfo, dest, op, this.ref, other.ref)) + + private[Chisel] def compop(sourceInfo: SourceInfo, op: PrimOp, other: Bits): Bool = + pushOp(DefPrim(sourceInfo, Bool(), op, this.ref, other.ref)) + private[Chisel] def redop(sourceInfo: SourceInfo, op: PrimOp): Bool = + pushOp(DefPrim(sourceInfo, Bool(), op, this.ref)) + + /** Returns this wire zero padded up to the specified width. + * + * @note for SInts only, this does sign extension + */ + final def pad(that: Int): this.type = macro SourceInfoTransform.thatArg + + def do_pad(that: Int)(implicit sourceInfo: SourceInfo): this.type = + binop(sourceInfo, cloneTypeWidth(this.width max Width(that)), PadOp, that) + + /** Returns this wire bitwise-inverted. */ + final def unary_~ (): Bits = macro SourceInfoWhiteboxTransform.noArg + + def do_unary_~ (implicit sourceInfo: SourceInfo): Bits + + + /** Shift left operation */ + // REVIEW TODO: redundant + // REVIEW TODO: should these return this.type or Bits? + final def << (that: BigInt): Bits = macro SourceInfoWhiteboxTransform.thatArg + + def do_<< (that: BigInt)(implicit sourceInfo: SourceInfo): 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. + */ + final def << (that: Int): Bits = macro SourceInfoWhiteboxTransform.thatArg + + def do_<< (that: Int)(implicit sourceInfo: SourceInfo): 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. + */ + final def << (that: UInt): Bits = macro SourceInfoWhiteboxTransform.thatArg + + def do_<< (that: UInt)(implicit sourceInfo: SourceInfo): Bits + + /** Shift right operation */ + // REVIEW TODO: redundant + final def >> (that: BigInt): Bits = macro SourceInfoWhiteboxTransform.thatArg + + def do_>> (that: BigInt)(implicit sourceInfo: SourceInfo): 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. + */ + final def >> (that: Int): Bits = macro SourceInfoWhiteboxTransform.thatArg + + def do_>> (that: Int)(implicit sourceInfo: SourceInfo): 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. + */ + final def >> (that: UInt): Bits = macro SourceInfoWhiteboxTransform.thatArg + + def do_>> (that: UInt)(implicit sourceInfo: SourceInfo): Bits + + /** Returns the contents of this wire as a [[Vec]] of [[Bool]]s. + */ + final def toBools(): Seq[Bool] = macro SourceInfoTransform.noArg + + def toBools(implicit sourceInfo: SourceInfo): Seq[Bool] = + Seq.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 + */ + final def asSInt(): SInt = macro SourceInfoTransform.noArg + + def do_asSInt(implicit sourceInfo: SourceInfo): 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 + */ + final def asUInt(): UInt = macro SourceInfoTransform.noArg + + def do_asUInt(implicit sourceInfo: SourceInfo): UInt + + /** Reinterpret cast to Bits. */ + final def asBits(): Bits = macro SourceInfoTransform.noArg + + def do_asBits(implicit sourceInfo: SourceInfo): Bits = asUInt() + + @deprecated("Use asSInt, which makes the reinterpret cast more explicit", "chisel3") + final def toSInt(): SInt = do_asSInt(DeprecatedSourceInfo) + @deprecated("Use asUInt, which makes the reinterpret cast more explicit", "chisel3") + final def toUInt(): UInt = do_asUInt(DeprecatedSourceInfo) + + final def toBool(): Bool = macro SourceInfoTransform.noArg + + def do_toBool(implicit sourceInfo: SourceInfo): 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. + */ + final def ## (that: Bits): UInt = macro SourceInfoTransform.thatArg + + def do_## (that: Bits)(implicit sourceInfo: SourceInfo): UInt = { + val w = this.width + that.width + pushOp(DefPrim(sourceInfo, UInt(w), ConcatOp, this.ref, that.ref)) + } + + @deprecated("Use asBits, which makes the reinterpret cast more explicit and actually returns Bits", "chisel3") + override def toBits: UInt = do_asUInt(DeprecatedSourceInfo) + + override def do_fromBits(that: Bits)(implicit sourceInfo: SourceInfo): this.type = { + val res = Wire(this, null).asInstanceOf[this.type] + res := that + 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). + */ + final def + (that: T): T = macro SourceInfoTransform.thatArg + + def do_+ (that: T)(implicit sourceInfo: SourceInfo): 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 + */ + final def * (that: T): T = macro SourceInfoTransform.thatArg + + def do_* (that: T)(implicit sourceInfo: SourceInfo): T + + /** Outputs the quotient of `this` and `b`. + * + * TODO: full rules + */ + final def / (that: T): T = macro SourceInfoTransform.thatArg + + def do_/ (that: T)(implicit sourceInfo: SourceInfo): T + + final def % (that: T): T = macro SourceInfoTransform.thatArg + + def do_% (that: T)(implicit sourceInfo: SourceInfo): T + + /** Outputs the difference of `this` and `b`. The resulting width is the max + * of the operands plus 1 (should not overflow). + */ + final def - (that: T): T = macro SourceInfoTransform.thatArg + + def do_- (that: T)(implicit sourceInfo: SourceInfo): T + + /** Outputs true if `this` < `b`. + */ + final def < (that: T): Bool = macro SourceInfoTransform.thatArg + + def do_< (that: T)(implicit sourceInfo: SourceInfo): Bool + + /** Outputs true if `this` <= `b`. + */ + final def <= (that: T): Bool = macro SourceInfoTransform.thatArg + + def do_<= (that: T)(implicit sourceInfo: SourceInfo): Bool + + /** Outputs true if `this` > `b`. + */ + final def > (that: T): Bool = macro SourceInfoTransform.thatArg + + def do_> (that: T)(implicit sourceInfo: SourceInfo): Bool + + /** Outputs true if `this` >= `b`. + */ + final def >= (that: T): Bool = macro SourceInfoTransform.thatArg + + def do_>= (that: T)(implicit sourceInfo: SourceInfo): Bool + + /** Outputs the minimum of `this` and `b`. The resulting width is the max of + * the operands. + */ + final def min(that: T): T = macro SourceInfoTransform.thatArg + + def do_min(that: T)(implicit sourceInfo: SourceInfo): T = + Mux(this < that, this.asInstanceOf[T], that) + + /** Outputs the maximum of `this` and `b`. The resulting width is the max of + * the operands. + */ + final def max(that: T): T = macro SourceInfoTransform.thatArg + + def do_max(that: T)(implicit sourceInfo: SourceInfo): T = + Mux(this < that, that, 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, width: Int): this.type = + UInt(value, width).asInstanceOf[this.type] + + override def := (that: Data)(implicit sourceInfo: SourceInfo): Unit = that match { + case _: UInt => this connect that + case _ => this badConnect that + } + + // TODO: refactor to share documentation with Num or add independent scaladoc + final def unary_- (): UInt = macro SourceInfoTransform.noArg + final def unary_-% (): UInt = macro SourceInfoTransform.noArg + + def do_unary_- (implicit sourceInfo: SourceInfo) : UInt = UInt(0) - this + def do_unary_-% (implicit sourceInfo: SourceInfo): UInt = UInt(0) -% this + + override def do_+ (that: UInt)(implicit sourceInfo: SourceInfo): UInt = this +% that + override def do_- (that: UInt)(implicit sourceInfo: SourceInfo): UInt = this -% that + override def do_/ (that: UInt)(implicit sourceInfo: SourceInfo): UInt = + binop(sourceInfo, UInt(this.width), DivideOp, that) + override def do_% (that: UInt)(implicit sourceInfo: SourceInfo): UInt = + binop(sourceInfo, UInt(this.width), RemOp, that) + override def do_* (that: UInt)(implicit sourceInfo: SourceInfo): UInt = + binop(sourceInfo, UInt(this.width + that.width), TimesOp, that) + + final def * (that: SInt): SInt = macro SourceInfoTransform.thatArg + def do_* (that: SInt)(implicit sourceInfo: SourceInfo): SInt = that * this + + final def +& (that: UInt): UInt = macro SourceInfoTransform.thatArg + final def +% (that: UInt): UInt = macro SourceInfoTransform.thatArg + final def -& (that: UInt): UInt = macro SourceInfoTransform.thatArg + final def -% (that: UInt): UInt = macro SourceInfoTransform.thatArg + + def do_+& (that: UInt)(implicit sourceInfo: SourceInfo): UInt = + binop(sourceInfo, UInt((this.width max that.width) + 1), AddOp, that) + def do_+% (that: UInt)(implicit sourceInfo: SourceInfo): UInt = + (this +& that).tail(1) + def do_-& (that: UInt)(implicit sourceInfo: SourceInfo): UInt = + binop(sourceInfo, UInt((this.width max that.width) + 1), SubOp, that) + def do_-% (that: UInt)(implicit sourceInfo: SourceInfo): UInt = + (this -& that).tail(1) + + final def & (that: UInt): UInt = macro SourceInfoTransform.thatArg + final def | (that: UInt): UInt = macro SourceInfoTransform.thatArg + final def ^ (that: UInt): UInt = macro SourceInfoTransform.thatArg + + def do_& (that: UInt)(implicit sourceInfo: SourceInfo): UInt = + binop(sourceInfo, UInt(this.width max that.width), BitAndOp, that) + def do_| (that: UInt)(implicit sourceInfo: SourceInfo): UInt = + binop(sourceInfo, UInt(this.width max that.width), BitOrOp, that) + def do_^ (that: UInt)(implicit sourceInfo: SourceInfo): UInt = + binop(sourceInfo, UInt(this.width max that.width), BitXorOp, that) + + /** Returns this wire bitwise-inverted. */ + def do_unary_~ (implicit sourceInfo: SourceInfo): UInt = + unop(sourceInfo, UInt(width = width), BitNotOp) + + // REVIEW TODO: Can this be defined on Bits? + final def orR(): Bool = macro SourceInfoTransform.noArg + final def andR(): Bool = macro SourceInfoTransform.noArg + final def xorR(): Bool = macro SourceInfoTransform.noArg + + def do_orR(implicit sourceInfo: SourceInfo): Bool = this != UInt(0) + def do_andR(implicit sourceInfo: SourceInfo): Bool = ~this === UInt(0) + def do_xorR(implicit sourceInfo: SourceInfo): Bool = redop(sourceInfo, XorReduceOp) + + override def do_< (that: UInt)(implicit sourceInfo: SourceInfo): Bool = compop(sourceInfo, LessOp, that) + override def do_> (that: UInt)(implicit sourceInfo: SourceInfo): Bool = compop(sourceInfo, GreaterOp, that) + override def do_<= (that: UInt)(implicit sourceInfo: SourceInfo): Bool = compop(sourceInfo, LessEqOp, that) + override def do_>= (that: UInt)(implicit sourceInfo: SourceInfo): Bool = compop(sourceInfo, GreaterEqOp, that) + + final def != (that: UInt): Bool = macro SourceInfoTransform.thatArg + final def =/= (that: UInt): Bool = macro SourceInfoTransform.thatArg + final def === (that: UInt): Bool = macro SourceInfoTransform.thatArg + + def do_!= (that: UInt)(implicit sourceInfo: SourceInfo): Bool = compop(sourceInfo, NotEqualOp, that) + def do_=/= (that: UInt)(implicit sourceInfo: SourceInfo): Bool = compop(sourceInfo, NotEqualOp, that) + def do_=== (that: UInt)(implicit sourceInfo: SourceInfo): Bool = compop(sourceInfo, EqualOp, that) + + final def unary_! () : Bool = macro SourceInfoTransform.noArg + + def do_unary_! (implicit sourceInfo: SourceInfo) : Bool = this === Bits(0) + + override def do_<< (that: Int)(implicit sourceInfo: SourceInfo): UInt = + binop(sourceInfo, UInt(this.width + that), ShiftLeftOp, that) + override def do_<< (that: BigInt)(implicit sourceInfo: SourceInfo): UInt = + this << that.toInt + override def do_<< (that: UInt)(implicit sourceInfo: SourceInfo): UInt = + binop(sourceInfo, UInt(this.width.dynamicShiftLeft(that.width)), DynamicShiftLeftOp, that) + override def do_>> (that: Int)(implicit sourceInfo: SourceInfo): UInt = + binop(sourceInfo, UInt(this.width.shiftRight(that)), ShiftRightOp, that) + override def do_>> (that: BigInt)(implicit sourceInfo: SourceInfo): UInt = + this >> that.toInt + override def do_>> (that: UInt)(implicit sourceInfo: SourceInfo): UInt = + binop(sourceInfo, UInt(this.width), DynamicShiftRightOp, that) + + final def bitSet(off: UInt, dat: Bool): UInt = macro UIntTransform.bitset + + def do_bitSet(off: UInt, dat: Bool)(implicit sourceInfo: SourceInfo): UInt = { + val bit = UInt(1, 1) << off + Mux(dat, this | bit, ~(~this | bit)) + } + + /** 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. + final def zext(): SInt = macro SourceInfoTransform.noArg + def do_zext(implicit sourceInfo: SourceInfo): SInt = + pushOp(DefPrim(sourceInfo, 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). + */ + override def do_asSInt(implicit sourceInfo: SourceInfo): SInt = + pushOp(DefPrim(sourceInfo, SInt(width), AsSIntOp, ref)) + override def do_asUInt(implicit sourceInfo: SourceInfo): 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)(implicit sourceInfo: SourceInfo): Unit = that match { + case _: SInt => this connect that + case _ => this badConnect that + } + + override private[Chisel] def fromInt(value: BigInt, width: Int): this.type = + SInt(value, width).asInstanceOf[this.type] + + final def unary_- (): SInt = macro SourceInfoTransform.noArg + final def unary_-% (): SInt = macro SourceInfoTransform.noArg + + def unary_- (implicit sourceInfo: SourceInfo): SInt = SInt(0) - this + def unary_-% (implicit sourceInfo: SourceInfo): SInt = SInt(0) -% this + + /** add (default - no growth) operator */ + override def do_+ (that: SInt)(implicit sourceInfo: SourceInfo): SInt = + this +% that + /** subtract (default - no growth) operator */ + override def do_- (that: SInt)(implicit sourceInfo: SourceInfo): SInt = + this -% that + override def do_* (that: SInt)(implicit sourceInfo: SourceInfo): SInt = + binop(sourceInfo, SInt(this.width + that.width), TimesOp, that) + override def do_/ (that: SInt)(implicit sourceInfo: SourceInfo): SInt = + binop(sourceInfo, SInt(this.width), DivideOp, that) + override def do_% (that: SInt)(implicit sourceInfo: SourceInfo): SInt = + binop(sourceInfo, SInt(this.width), RemOp, that) + + final def * (that: UInt): SInt = macro SourceInfoTransform.thatArg + def do_* (that: UInt)(implicit sourceInfo: SourceInfo): SInt = + binop(sourceInfo, SInt(this.width + that.width), TimesOp, that) + + /** add (width +1) operator */ + final def +& (that: SInt): SInt = macro SourceInfoTransform.thatArg + /** add (no growth) operator */ + final def +% (that: SInt): SInt = macro SourceInfoTransform.thatArg + /** subtract (width +1) operator */ + final def -& (that: SInt): SInt = macro SourceInfoTransform.thatArg + /** subtract (no growth) operator */ + final def -% (that: SInt): SInt = macro SourceInfoTransform.thatArg + + def do_+& (that: SInt)(implicit sourceInfo: SourceInfo): SInt = + binop(sourceInfo, SInt((this.width max that.width) + 1), AddOp, that) + def do_+% (that: SInt)(implicit sourceInfo: SourceInfo): SInt = + (this +& that).tail(1).asSInt + def do_-& (that: SInt)(implicit sourceInfo: SourceInfo): SInt = + binop(sourceInfo, SInt((this.width max that.width) + 1), SubOp, that) + def do_-% (that: SInt)(implicit sourceInfo: SourceInfo): SInt = + (this -& that).tail(1).asSInt + + final def & (that: SInt): SInt = macro SourceInfoTransform.thatArg + final def | (that: SInt): SInt = macro SourceInfoTransform.thatArg + final def ^ (that: SInt): SInt = macro SourceInfoTransform.thatArg + + def do_& (that: SInt)(implicit sourceInfo: SourceInfo): SInt = + binop(sourceInfo, UInt(this.width max that.width), BitAndOp, that).asSInt + def do_| (that: SInt)(implicit sourceInfo: SourceInfo): SInt = + binop(sourceInfo, UInt(this.width max that.width), BitOrOp, that).asSInt + def do_^ (that: SInt)(implicit sourceInfo: SourceInfo): SInt = + binop(sourceInfo, UInt(this.width max that.width), BitXorOp, that).asSInt + + /** Returns this wire bitwise-inverted. */ + def do_unary_~ (implicit sourceInfo: SourceInfo): SInt = + unop(sourceInfo, UInt(width = width), BitNotOp).asSInt + + override def do_< (that: SInt)(implicit sourceInfo: SourceInfo): Bool = compop(sourceInfo, LessOp, that) + override def do_> (that: SInt)(implicit sourceInfo: SourceInfo): Bool = compop(sourceInfo, GreaterOp, that) + override def do_<= (that: SInt)(implicit sourceInfo: SourceInfo): Bool = compop(sourceInfo, LessEqOp, that) + override def do_>= (that: SInt)(implicit sourceInfo: SourceInfo): Bool = compop(sourceInfo, GreaterEqOp, that) + + final def != (that: SInt): Bool = macro SourceInfoTransform.thatArg + final def =/= (that: SInt): Bool = macro SourceInfoTransform.thatArg + final def === (that: SInt): Bool = macro SourceInfoTransform.thatArg + + def do_!= (that: SInt)(implicit sourceInfo: SourceInfo): Bool = compop(sourceInfo, NotEqualOp, that) + def do_=/= (that: SInt)(implicit sourceInfo: SourceInfo): Bool = compop(sourceInfo, NotEqualOp, that) + def do_=== (that: SInt)(implicit sourceInfo: SourceInfo): Bool = compop(sourceInfo, EqualOp, that) + + final def abs(): UInt = macro SourceInfoTransform.noArg + + def do_abs(implicit sourceInfo: SourceInfo): UInt = Mux(this < SInt(0), (-this).asUInt, this.asUInt) + + override def do_<< (that: Int)(implicit sourceInfo: SourceInfo): SInt = + binop(sourceInfo, SInt(this.width + that), ShiftLeftOp, that) + override def do_<< (that: BigInt)(implicit sourceInfo: SourceInfo): SInt = + this << that.toInt + override def do_<< (that: UInt)(implicit sourceInfo: SourceInfo): SInt = + binop(sourceInfo, SInt(this.width.dynamicShiftLeft(that.width)), DynamicShiftLeftOp, that) + override def do_>> (that: Int)(implicit sourceInfo: SourceInfo): SInt = + binop(sourceInfo, SInt(this.width.shiftRight(that)), ShiftRightOp, that) + override def do_>> (that: BigInt)(implicit sourceInfo: SourceInfo): SInt = + this >> that.toInt + override def do_>> (that: UInt)(implicit sourceInfo: SourceInfo): SInt = + binop(sourceInfo, SInt(this.width), DynamicShiftRightOp, that) + + override def do_asUInt(implicit sourceInfo: SourceInfo): UInt = pushOp(DefPrim(sourceInfo, UInt(this.width), AsUIntOp, ref)) + override def do_asSInt(implicit sourceInfo: SourceInfo): 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, width: Int): this.type = { + require((value == 0 || value == 1) && width == 1) + Bool(value == 1).asInstanceOf[this.type] + } + + // REVIEW TODO: Why does this need to exist and have different conventions + // than Bits? + final def & (that: Bool): Bool = macro SourceInfoTransform.thatArg + final def | (that: Bool): Bool = macro SourceInfoTransform.thatArg + final def ^ (that: Bool): Bool = macro SourceInfoTransform.thatArg + + def do_& (that: Bool)(implicit sourceInfo: SourceInfo): Bool = + binop(sourceInfo, Bool(), BitAndOp, that) + def do_| (that: Bool)(implicit sourceInfo: SourceInfo): Bool = + binop(sourceInfo, Bool(), BitOrOp, that) + def do_^ (that: Bool)(implicit sourceInfo: SourceInfo): Bool = + binop(sourceInfo, Bool(), BitXorOp, that) + + /** Returns this wire bitwise-inverted. */ + override def do_unary_~ (implicit sourceInfo: SourceInfo): Bool = + unop(sourceInfo, Bool(), BitNotOp) + + /** Outputs the logical OR of two Bools. + */ + def || (that: Bool): Bool = macro SourceInfoTransform.thatArg + + def do_|| (that: Bool)(implicit sourceInfo: SourceInfo): Bool = this | that + + /** Outputs the logical AND of two Bools. + */ + def && (that: Bool): Bool = macro SourceInfoTransform.thatArg + + def do_&& (that: Bool)(implicit sourceInfo: SourceInfo): 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 = macro MuxTransform.apply[T] + + def do_apply[T <: Data](cond: Bool, con: T, alt: T)(implicit sourceInfo: SourceInfo): 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)(implicit sourceInfo: SourceInfo): 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(sourceInfo, d, MultiplexOp, cond.ref, con.ref, alt.ref)) + } + + private def doAggregateMux[T <: Data](cond: Bool, con: T, alt: T)(implicit sourceInfo: SourceInfo): 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/chisel3/core/BlackBox.scala b/chiselFrontend/src/main/scala/chisel3/core/BlackBox.scala new file mode 100644 index 00000000..b634f021 --- /dev/null +++ b/chiselFrontend/src/main/scala/chisel3/core/BlackBox.scala @@ -0,0 +1,55 @@ +// See LICENSE for license details. + +package Chisel + +import internal.Builder.pushCommand +import internal.firrtl.{ModuleIO, DefInvalid} +import internal.sourceinfo.SourceInfo + +/** 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(implicit sourceInfo: SourceInfo): this.type = _parent match { + case Some(p) => { + // Just init instance inputs + for((_,port) <- ports) pushCommand(DefInvalid(sourceInfo, 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/chisel3/core/Data.scala b/chiselFrontend/src/main/scala/chisel3/core/Data.scala new file mode 100644 index 00000000..d16843f7 --- /dev/null +++ b/chiselFrontend/src/main/scala/chisel3/core/Data.scala @@ -0,0 +1,161 @@ +// See LICENSE for license details. + +package Chisel + +import scala.language.experimental.macros + +import internal._ +import internal.Builder.pushCommand +import internal.firrtl._ +import internal.sourceinfo.{SourceInfo, DeprecatedSourceInfo, UnlocatableSourceInfo, WireTransform, SourceInfoTransform} + +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)(implicit sourceInfo: SourceInfo): Unit = + throwException(s"cannot connect ${this} and ${that}") + private[Chisel] def connect(that: Data)(implicit sourceInfo: SourceInfo): Unit = + pushCommand(Connect(sourceInfo, this.lref, that.ref)) + private[Chisel] def bulkConnect(that: Data)(implicit sourceInfo: SourceInfo): Unit = + pushCommand(BulkConnect(sourceInfo, 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)(implicit sourceInfo: SourceInfo): Unit = this badConnect that + + def <> (that: Data)(implicit sourceInfo: SourceInfo): 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(that: Bits): this.type = macro SourceInfoTransform.thatArg + + def do_fromBits(that: Bits)(implicit sourceInfo: SourceInfo): this.type = { + var i = 0 + val wire = Wire(this.cloneType) + val bits = + if (that.width.known && that.width.get >= wire.width.get) { + that + } else { + Wire(that.cloneTypeWidth(wire.width), init = that) + } + 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). + */ + @deprecated("Use asBits, which makes the reinterpret cast more explicit and actually returns Bits", "chisel3") + def toBits(): UInt = SeqUtils.do_asUInt(this.flatten)(DeprecatedSourceInfo) +} + +object Wire { + def apply[T <: Data](t: T): T = macro WireTransform.apply[T] + + // No source info since Scala macros don't yet support named / default arguments. + def apply[T <: Data](dummy: Int = 0, init: T): T = + do_apply(null.asInstanceOf[T], init)(UnlocatableSourceInfo) + + // No source info since Scala macros don't yet support named / default arguments. + def apply[T <: Data](t: T, init: T): T = + do_apply(t, init)(UnlocatableSourceInfo) + + def do_apply[T <: Data](t: T, init: T)(implicit sourceInfo: SourceInfo): T = { + val x = Reg.makeType(t, null.asInstanceOf[T], init) + pushCommand(DefWire(sourceInfo, x)) + pushCommand(DefInvalid(sourceInfo, 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)(implicit sourceInfo: SourceInfo): Unit = that match { + case _: Clock => this connect that + case _ => this badConnect that + } +} diff --git a/chiselFrontend/src/main/scala/chisel3/core/Mem.scala b/chiselFrontend/src/main/scala/chisel3/core/Mem.scala new file mode 100644 index 00000000..e34d5499 --- /dev/null +++ b/chiselFrontend/src/main/scala/chisel3/core/Mem.scala @@ -0,0 +1,134 @@ +// See LICENSE for license details. + +package Chisel + +import scala.language.experimental.macros + +import internal._ +import internal.Builder.pushCommand +import internal.firrtl._ +import internal.sourceinfo.{SourceInfo, DeprecatedSourceInfo, UnlocatableSourceInfo, MemTransform} + +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] = do_apply(size, t)(UnlocatableSourceInfo) + + /** 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] = macro MemTransform.apply[T] + + def do_apply[T <: Data](size: Int, t: T)(implicit sourceInfo: SourceInfo): Mem[T] = { + val mt = t.cloneType + val mem = new Mem(mt, size) + pushCommand(DefMemory(sourceInfo, 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(UnlocatableSourceInfo, 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(UnlocatableSourceInfo, 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 = { + implicit val sourceInfo = UnlocatableSourceInfo + makePort(UnlocatableSourceInfo, 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: Seq[Bool]) (implicit evidence: T <:< Vec[_]): Unit = { + implicit val sourceInfo = UnlocatableSourceInfo + val accessor = makePort(sourceInfo, 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(sourceInfo: SourceInfo, idx: UInt, dir: MemPortDirection): T = + pushCommand(DefMemPort(sourceInfo, + 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] = do_apply(size, t)(DeprecatedSourceInfo) + + /** 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] = macro MemTransform.apply[T] + + def do_apply[T <: Data](size: Int, t: T)(implicit sourceInfo: SourceInfo): SeqMem[T] = { + val mt = t.cloneType + val mem = new SeqMem(mt, size) + pushCommand(DefSeqMemory(sourceInfo, 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 = { + implicit val sourceInfo = UnlocatableSourceInfo + val a = Wire(UInt()) + when (enable) { a := addr } + read(a) + } +} diff --git a/chiselFrontend/src/main/scala/chisel3/core/Module.scala b/chiselFrontend/src/main/scala/chisel3/core/Module.scala new file mode 100644 index 00000000..e2101538 --- /dev/null +++ b/chiselFrontend/src/main/scala/chisel3/core/Module.scala @@ -0,0 +1,119 @@ +// See LICENSE for license details. + +package Chisel + +import scala.collection.mutable.{ArrayBuffer, HashSet} +import scala.language.experimental.macros + +import internal._ +import internal.Builder.pushCommand +import internal.Builder.dynamicContext +import internal.firrtl._ +import internal.sourceinfo.{SourceInfo, InstTransform, UnlocatableSourceInfo} + +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 = macro InstTransform.apply[T] + + def do_apply[T <: Module](bc: => T)(implicit sourceInfo: SourceInfo): T = { + // Don't generate source info referencing parents inside a module, sincce this interferes with + // module de-duplication in FIRRTL emission. + val childSourceInfo = UnlocatableSourceInfo + + val parent = dynamicContext.currentModule + val m = bc.setRefs() + m._commands.prepend(DefInvalid(childSourceInfo, m.io.ref)) // init module outputs + dynamicContext.currentModule = parent + val ports = m.computePorts + Builder.components += Component(m, m.name, ports, m._commands) + pushCommand(DefInstance(sourceInfo, m, ports)) + m.setupInParent(childSourceInfo) + } +} + +/** 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(Option(_clock), None) + def this(_reset: Bool) = this(None, Option(_reset)) + def this(_clock: Clock, _reset: Bool) = this(Option(_clock), Option(_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(implicit sourceInfo: SourceInfo): this.type = { + _parent match { + case Some(p) => { + pushCommand(DefInvalid(sourceInfo, 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 _ => + } + + // For Module instances we haven't named, suggest the name of the Module + _ids foreach { + case m: Module => m.suggestName(m.name) + 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/chisel3/core/MonoConnect.scala b/chiselFrontend/src/main/scala/chisel3/core/MonoConnect.scala new file mode 100644 index 00000000..27da965b --- /dev/null +++ b/chiselFrontend/src/main/scala/chisel3/core/MonoConnect.scala @@ -0,0 +1,172 @@ +package Chisel + +import internal.Builder.pushCommand +import internal.firrtl.Connect +import scala.language.experimental.macros +import internal.sourceinfo.{SourceInfo, DeprecatedSourceInfo, UnlocatableSourceInfo, WireTransform, SourceInfoTransform} + +/** +* MonoConnect.connect executes a mono-directional connection element-wise. +* +* Note that this isn't commutative. There is an explicit source and sink +* already determined before this function is called. +* +* The connect operation will recurse down the left Data (with the right Data). +* An exception will be thrown if a movement through the left cannot be matched +* in the right. The right side is allowed to have extra Bundle fields. +* Vecs must still be exactly the same size. +* +* See elemConnect for details on how the root connections are issued. +* +* Note that a valid sink must be writable so, one of these must hold: +* - Is an internal writable node (Reg or Wire) +* - Is an output of the current module +* - Is an input of a submodule of the current module +* +* Note that a valid source must be readable so, one of these must hold: +* - Is an internal readable node (Reg, Wire, Op) +* - Is a literal +* - Is a port of the current module or submodule of the current module +*/ + +object MonoConnect { + // These are all the possible exceptions that can be thrown. + case class MonoConnectException(message: String) extends Exception(message) + // These are from element-level connection + def UnreadableSourceException = + MonoConnectException(": Source is unreadable from current module.") + def UnwritableSinkException = + MonoConnectException(": Sink is unwriteable by current module.") + def UnknownRelationException = + MonoConnectException(": Sink or source unavailable to current module.") + // These are when recursing down aggregate types + def MismatchedVecException = + MonoConnectException(": Sink and Source are different length Vecs.") + def MissingFieldException(field: String) = + MonoConnectException(s": Source Bundle missing field ($field).") + def MismatchedException(sink: String, source: String) = + MonoConnectException(s": Sink ($sink) and Source ($source) have different types.") + + /** This function is what recursively tries to connect a sink and source together + * + * There is some cleverness in the use of internal try-catch to catch exceptions + * during the recursive decent and then rethrow them with extra information added. + * This gives the user a 'path' to where in the connections things went wrong. + */ + def connect(sourceInfo: SourceInfo, sink: Data, source: Data, context_mod: Module): Unit = + (sink, source) match { + // Handle element case (root case) + case (sink_e: Element, source_e: Element) => { + elemConnect(sourceInfo, sink_e, source_e, context_mod) + // TODO(twigg): Verify the element-level classes are connectable + } + // Handle Vec case + case (sink_v: Vec[Data @unchecked], source_v: Vec[Data @unchecked]) => { + if(sink_v.length != source_v.length) { throw MismatchedVecException } + for(idx <- 0 until sink_v.length) { + try { + connect(sourceInfo, sink_v(idx), source_v(idx), context_mod) + } catch { + case MonoConnectException(message) => throw MonoConnectException(s"($idx)$message") + } + } + } + // Handle Bundle case + case (sink_b: Bundle, source_b: Bundle) => { + // For each field, descend with right + for((field, sink_sub) <- sink_b.elements) { + try { + source_b.elements.get(field) match { + case Some(source_sub) => connect(sourceInfo, sink_sub, source_sub, context_mod) + case None => throw MissingFieldException(field) + } + } catch { + case MonoConnectException(message) => throw MonoConnectException(s".$field$message") + } + } + } + // Sink and source are different subtypes of data so fail + case (sink, source) => throw MismatchedException(sink.toString, source.toString) + } + + // This function (finally) issues the connection operation + private def issueConnect(sink: Element, source: Element)(implicit sourceInfo: SourceInfo): Unit = { + pushCommand(Connect(sourceInfo, sink.lref, source.ref)) + } + + // This function checks if element-level connection operation allowed. + // Then it either issues it or throws the appropriate exception. + def elemConnect(implicit sourceInfo: SourceInfo, sink: Element, source: Element, context_mod: Module): Unit = { + import Direction.{Input, Output} // Using extensively so import these + // If source has no location, assume in context module + // This can occur if is a literal, unbound will error previously + val sink_mod: Module = sink.binding.location.getOrElse(throw UnwritableSinkException) + val source_mod: Module = source.binding.location.getOrElse(context_mod) + + val sink_direction: Option[Direction] = sink.binding.direction + val source_direction: Option[Direction] = source.binding.direction + // None means internal + + // CASE: Context is same module that both left node and right node are in + if( (context_mod == sink_mod) && (context_mod == source_mod) ) { + (sink_direction, source_direction) match { + // SINK SOURCE + // CURRENT MOD CURRENT MOD + case (Some(Output), _) => issueConnect(sink, source) + case (None, _) => issueConnect(sink, source) + case (Some(Input), _) => throw UnwritableSinkException + } + } + + // CASE: Context is same module as sink node and right node is in a child module + else if( (sink_mod == context_mod) && + (source_mod._parent.map(_ == context_mod).getOrElse(false)) ) { + // Thus, right node better be a port node and thus have a direction + (sink_direction, source_direction) match { + // SINK SOURCE + // CURRENT MOD CHILD MOD + case (None, Some(Output)) => issueConnect(sink, source) + case (None, Some(Input)) => issueConnect(sink, source) + case (Some(Output), Some(Output)) => issueConnect(sink, source) + case (Some(Output), Some(Input)) => issueConnect(sink, source) + case (_, None) => throw UnreadableSourceException + case (Some(Input), _) => throw UnwritableSinkException + } + } + + // CASE: Context is same module as source node and sink node is in child module + else if( (source_mod == context_mod) && + (sink_mod._parent.map(_ == context_mod).getOrElse(false)) ) { + // Thus, left node better be a port node and thus have a direction + (sink_direction, source_direction) match { + // SINK SOURCE + // CHILD MOD CURRENT MOD + case (Some(Input), _) => issueConnect(sink, source) + case (Some(Output), _) => throw UnwritableSinkException + case (None, _) => throw UnwritableSinkException + } + } + + // CASE: Context is the parent module of both the module containing sink node + // and the module containing source node + // Note: This includes case when sink and source in same module but in parent + else if( (sink_mod._parent.map(_ == context_mod).getOrElse(false)) && + (source_mod._parent.map(_ == context_mod).getOrElse(false)) + ) { + // Thus both nodes must be ports and have a direction + (sink_direction, source_direction) match { + // SINK SOURCE + // CHILD MOD CHILD MOD + case (Some(Input), Some(Input)) => issueConnect(sink, source) + case (Some(Input), Some(Output)) => issueConnect(sink, source) + case (Some(Output), _) => throw UnwritableSinkException + case (_, None) => throw UnreadableSourceException + case (None, _) => throw UnwritableSinkException + } + } + + // Not quite sure where left and right are compared to current module + // so just error out + else throw UnknownRelationException + } +} diff --git a/chiselFrontend/src/main/scala/chisel3/core/Printf.scala b/chiselFrontend/src/main/scala/chisel3/core/Printf.scala new file mode 100644 index 00000000..f068f637 --- /dev/null +++ b/chiselFrontend/src/main/scala/chisel3/core/Printf.scala @@ -0,0 +1,36 @@ +// See LICENSE for license details. + +package Chisel + +import scala.language.experimental.macros + +import internal._ +import internal.Builder.pushCommand +import internal.firrtl._ +import internal.sourceinfo.SourceInfo + +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*)(implicit sourceInfo: SourceInfo) { + when (!(Builder.dynamicContext.currentModule.get.reset)) { + printfWithoutReset(fmt, data:_*) + } + } + + private[Chisel] def printfWithoutReset(fmt: String, data: Bits*)(implicit sourceInfo: SourceInfo) { + val clock = Builder.dynamicContext.currentModule.get.clock + pushCommand(Printf(sourceInfo, Node(clock), fmt, data.map((d: Bits) => d.ref))) + } +} diff --git a/chiselFrontend/src/main/scala/chisel3/core/Reg.scala b/chiselFrontend/src/main/scala/chisel3/core/Reg.scala new file mode 100644 index 00000000..c8faa5c9 --- /dev/null +++ b/chiselFrontend/src/main/scala/chisel3/core/Reg.scala @@ -0,0 +1,71 @@ +// See LICENSE for license details. + +package Chisel + +import internal._ +import internal.Builder.pushCommand +import internal.firrtl._ +import internal.sourceinfo.{SourceInfo, UnlocatableSourceInfo} + +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 = + // Scala macros can't (yet) handle named or default arguments. + do_apply(t, next, init)(UnlocatableSourceInfo) + + /** 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]) + + def do_apply[T <: Data](t: T, next: T, init: T)(implicit sourceInfo: SourceInfo): 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(sourceInfo, x, clock)) + } else { + pushCommand(DefRegInit(sourceInfo, x, clock, Node(x._parent.get.reset), init.ref)) + } + if (next != null) { + x := next + } + x + } +} diff --git a/chiselFrontend/src/main/scala/chisel3/core/SeqUtils.scala b/chiselFrontend/src/main/scala/chisel3/core/SeqUtils.scala new file mode 100644 index 00000000..9a15fd5f --- /dev/null +++ b/chiselFrontend/src/main/scala/chisel3/core/SeqUtils.scala @@ -0,0 +1,59 @@ +// See LICENSE for license details. + +package Chisel + +import scala.language.experimental.macros + +import internal.sourceinfo.{SourceInfo, SourceInfoTransform} + +private[Chisel] object SeqUtils { + /** Equivalent to Cat(r(n-1), ..., r(0)) */ + def asUInt[T <: Bits](in: Seq[T]): UInt = macro SourceInfoTransform.inArg + + def do_asUInt[T <: Bits](in: Seq[T])(implicit sourceInfo: SourceInfo): 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 = macro SourceInfoTransform.inArg + + def do_count(in: Seq[Bool])(implicit sourceInfo: SourceInfo): 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 <: Data](in: Seq[(Bool, T)]): T = macro SourceInfoTransform.inArg + + def do_priorityMux[T <: Data](in: Seq[(Bool, T)])(implicit sourceInfo: SourceInfo): 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 = macro SourceInfoTransform.inArg + + def do_oneHotMux[T <: Data](in: Iterable[(Bool, T)])(implicit sourceInfo: SourceInfo): 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/chisel3/core/When.scala b/chiselFrontend/src/main/scala/chisel3/core/When.scala new file mode 100644 index 00000000..90b3d1a5 --- /dev/null +++ b/chiselFrontend/src/main/scala/chisel3/core/When.scala @@ -0,0 +1,59 @@ +// See LICENSE for license details. + +package Chisel + +import scala.language.experimental.macros + +import internal._ +import internal.Builder.pushCommand +import internal.firrtl._ +import internal.sourceinfo.{SourceInfo} + +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)(implicit sourceInfo: SourceInfo): WhenContext = { + new WhenContext(sourceInfo, 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. + */ +final class WhenContext(sourceInfo: SourceInfo, 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)(implicit sourceInfo: SourceInfo): WhenContext = { + new WhenContext(sourceInfo, 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)(implicit sourceInfo: SourceInfo): Unit = + new WhenContext(sourceInfo, prevCond, null, block) + + pushCommand(WhenBegin(sourceInfo, cond.ref)) + block + pushCommand(WhenEnd(sourceInfo)) +} diff --git a/chiselFrontend/src/main/scala/chisel3/internal/Builder.scala b/chiselFrontend/src/main/scala/chisel3/internal/Builder.scala new file mode 100644 index 00000000..d0e28b7c --- /dev/null +++ b/chiselFrontend/src/main/scala/chisel3/internal/Builder.scala @@ -0,0 +1,123 @@ +// 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 getOrElse (new DynamicContext) + 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/chisel3/internal/Error.scala b/chiselFrontend/src/main/scala/chisel3/internal/Error.scala new file mode 100644 index 00000000..6c4c0880 --- /dev/null +++ b/chiselFrontend/src/main/scala/chisel3/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/chisel3/internal/SourceInfo.scala b/chiselFrontend/src/main/scala/chisel3/internal/SourceInfo.scala new file mode 100644 index 00000000..66bfc7a4 --- /dev/null +++ b/chiselFrontend/src/main/scala/chisel3/internal/SourceInfo.scala @@ -0,0 +1,51 @@ +// See LICENSE for license details. + +// This file contains macros for adding source locators at the point of invocation. +// +// This is not part of coreMacros to disallow this macro from being implicitly invoked in Chisel +// frontend (and generating source locators in Chisel core), which is almost certainly a bug. +// +// Note: While these functions and definitions are not private (macros can't be +// private), these are NOT meant to be part of the public API (yet) and no +// forward compatibility guarantees are made. +// A future revision may stabilize the source locator API to allow library +// writers to append source locator information at the point of a library +// function invocation. + +package Chisel.internal.sourceinfo + +import scala.language.experimental.macros +import scala.reflect.macros.blackbox.Context + +/** Abstract base class for generalized source information. + */ +sealed trait SourceInfo + +sealed trait NoSourceInfo extends SourceInfo + +/** For when source info can't be generated because of a technical limitation, like for Reg because + * Scala macros don't support named or default arguments. + */ +case object UnlocatableSourceInfo extends NoSourceInfo + +/** For when source info isn't generated because the function is deprecated and we're lazy. + */ +case object DeprecatedSourceInfo extends NoSourceInfo + +/** For FIRRTL lines from a Scala source line. + */ +case class SourceLine(filename: String, line: Int, col: Int) extends SourceInfo + +/** Provides a macro that returns the source information at the invocation point. + */ +object SourceInfoMacro { + def generate_source_info(c: Context): c.Tree = { + import c.universe._ + val p = c.enclosingPosition + q"_root_.Chisel.internal.sourceinfo.SourceLine(${p.source.file.name}, ${p.line}, ${p.column})" + } +} + +object SourceInfo { + implicit def materialize: SourceInfo = macro SourceInfoMacro.generate_source_info +} diff --git a/chiselFrontend/src/main/scala/chisel3/internal/firrtl/IR.scala b/chiselFrontend/src/main/scala/chisel3/internal/firrtl/IR.scala new file mode 100644 index 00000000..62784cee --- /dev/null +++ b/chiselFrontend/src/main/scala/chisel3/internal/firrtl/IR.scala @@ -0,0 +1,188 @@ +// See LICENSE for license details. + +package Chisel.internal.firrtl +import Chisel._ +import Chisel.internal._ +import Chisel.internal.sourceinfo.{SourceInfo, NoSourceInfo} + +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 { + def sourceInfo: SourceInfo +} +abstract class Definition extends Command { + def id: HasId + def name: String = id.getRef.name +} +case class DefPrim[T <: Data](sourceInfo: SourceInfo, id: T, op: PrimOp, args: Arg*) extends Definition +case class DefInvalid(sourceInfo: SourceInfo, arg: Arg) extends Command +case class DefWire(sourceInfo: SourceInfo, id: Data) extends Definition +case class DefReg(sourceInfo: SourceInfo, id: Data, clock: Arg) extends Definition +case class DefRegInit(sourceInfo: SourceInfo, id: Data, clock: Arg, reset: Arg, init: Arg) extends Definition +case class DefMemory(sourceInfo: SourceInfo, id: HasId, t: Data, size: Int) extends Definition +case class DefSeqMemory(sourceInfo: SourceInfo, id: HasId, t: Data, size: Int) extends Definition +case class DefMemPort[T <: Data](sourceInfo: SourceInfo, id: T, source: Node, dir: MemPortDirection, index: Arg, clock: Arg) extends Definition +case class DefInstance(sourceInfo: SourceInfo, id: Module, ports: Seq[Port]) extends Definition +case class WhenBegin(sourceInfo: SourceInfo, pred: Arg) extends Command +case class WhenEnd(sourceInfo: SourceInfo) extends Command +case class Connect(sourceInfo: SourceInfo, loc: Node, exp: Arg) extends Command +case class BulkConnect(sourceInfo: SourceInfo, loc1: Node, loc2: Node) extends Command +case class ConnectInit(sourceInfo: SourceInfo, loc: Node, exp: Arg) extends Command +case class Stop(sourceInfo: SourceInfo, 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(sourceInfo: SourceInfo, 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]) diff --git a/coreMacros/src/main/scala/Chisel/internal/sourceinfo/SourceInfoTransform.scala b/coreMacros/src/main/scala/Chisel/internal/sourceinfo/SourceInfoTransform.scala deleted file mode 100644 index 82ad5b9e..00000000 --- a/coreMacros/src/main/scala/Chisel/internal/sourceinfo/SourceInfoTransform.scala +++ /dev/null @@ -1,156 +0,0 @@ -// See LICENSE for license details. - -// This file transform macro definitions to explicitly add implicit source info to Chisel method -// calls. - -package Chisel.internal.sourceinfo - -import scala.language.experimental.macros -import scala.reflect.macros.blackbox.Context -import scala.reflect.macros.whitebox - - -/** Transforms a function call so that it can both provide implicit-style source information and - * have a chained apply call. Without macros, only one is possible, since having a implicit - * argument in the definition will cause the compiler to interpret a chained apply as an - * explicit implicit argument and give type errors. - * - * Instead of an implicit argument, the public-facing function no longer takes a SourceInfo at all. - * The macro transforms the public-facing function into a call to an internal function that takes - * an explicit SourceInfo by inserting an implicitly[SourceInfo] as the explicit argument. - */ -trait SourceInfoTransformMacro { - val c: Context - import c.universe._ - def thisObj = c.prefix.tree - def implicitSourceInfo = q"implicitly[_root_.Chisel.internal.sourceinfo.SourceInfo]" -} - -class WireTransform(val c: Context) extends SourceInfoTransformMacro { - import c.universe._ - def apply[T: c.WeakTypeTag](t: c.Tree): c.Tree = { - val tpe = weakTypeOf[T] - q"$thisObj.do_apply($t, null.asInstanceOf[$tpe])($implicitSourceInfo)" - } -} - -class UIntTransform(val c: Context) extends SourceInfoTransformMacro { - import c.universe._ - def bitset(off: c.Tree, dat: c.Tree): c.Tree = { - q"$thisObj.do_bitSet($off, $dat)($implicitSourceInfo)" - } -} - -// Module instantiation transform -class InstTransform(val c: Context) extends SourceInfoTransformMacro { - import c.universe._ - def apply[T: c.WeakTypeTag](bc: c.Tree): c.Tree = { - q"$thisObj.do_apply($bc)($implicitSourceInfo)" - } -} - -class MemTransform(val c: Context) extends SourceInfoTransformMacro { - import c.universe._ - def apply[T: c.WeakTypeTag](size: c.Tree, t: c.Tree): c.Tree = { - q"$thisObj.do_apply($size, $t)($implicitSourceInfo)" - } -} - -class RegTransform(val c: Context) extends SourceInfoTransformMacro { - import c.universe._ - def apply[T: c.WeakTypeTag](t: c.Tree): c.Tree = { - val tpe = weakTypeOf[T] - q"$thisObj.do_apply($t, null.asInstanceOf[$tpe], null.asInstanceOf[$tpe])($implicitSourceInfo)" - } -} - -class MuxTransform(val c: Context) extends SourceInfoTransformMacro { - import c.universe._ - def apply[T: c.WeakTypeTag](cond: c.Tree, con: c.Tree, alt: c.Tree): c.Tree = { - val tpe = weakTypeOf[T] - q"$thisObj.do_apply[$tpe]($cond, $con, $alt)($implicitSourceInfo)" - } -} - -class VecTransform(val c: Context) extends SourceInfoTransformMacro { - import c.universe._ - def apply_elts(elts: c.Tree): c.Tree = { - q"$thisObj.do_apply($elts)($implicitSourceInfo)" - } - def apply_elt0(elt0: c.Tree, elts: c.Tree*): c.Tree = { - q"$thisObj.do_apply($elt0, ..$elts)($implicitSourceInfo)" - } - def tabulate(n: c.Tree)(gen: c.Tree): c.Tree = { - q"$thisObj.do_tabulate($n)($gen)($implicitSourceInfo)" - } - def fill(n: c.Tree)(gen: c.Tree): c.Tree = { - q"$thisObj.do_fill($n)($gen)($implicitSourceInfo)" - } - def contains(x: c.Tree)(ev: c.Tree): c.Tree = { - q"$thisObj.do_contains($x)($implicitSourceInfo, $ev)" - } -} - -/** "Automatic" source information transform / insertion macros, which generate the function name - * based on the macro invocation (instead of explicitly writing out every transform). - */ -abstract class AutoSourceTransform extends SourceInfoTransformMacro { - import c.universe._ - /** Returns the TermName of the transformed function, which is the applied function name with do_ - * prepended. - */ - def doFuncTerm = { - val funcName = c.macroApplication match { - case q"$_.$funcName[..$_](...$_)" => funcName - case _ => throw new Exception(s"Chisel Internal Error: Could not resolve function name from macro application: ${showCode(c.macroApplication)}") - } - TermName("do_" + funcName) - } -} - -class SourceInfoTransform(val c: Context) extends AutoSourceTransform { - import c.universe._ - - def noArg(): c.Tree = { - q"$thisObj.$doFuncTerm($implicitSourceInfo)" - } - - def thatArg(that: c.Tree): c.Tree = { - q"$thisObj.$doFuncTerm($that)($implicitSourceInfo)" - } - - def nArg(n: c.Tree): c.Tree = { - q"$thisObj.$doFuncTerm($n)($implicitSourceInfo)" - } - - def pArg(p: c.Tree): c.Tree = { - q"$thisObj.$doFuncTerm($p)($implicitSourceInfo)" - } - - def inArg(in: c.Tree): c.Tree = { - q"$thisObj.$doFuncTerm($in)($implicitSourceInfo)" - } - - def xArg(x: c.Tree): c.Tree = { - q"$thisObj.$doFuncTerm($x)($implicitSourceInfo)" - } - - def xyArg(x: c.Tree, y: c.Tree): c.Tree = { - q"$thisObj.$doFuncTerm($x, $y)($implicitSourceInfo)" - } -} - -/** Special whitebox version of the blackbox SourceInfoTransform, used when fun things need to happen to satisfy the - * type system while preventing the use of macro overrides. - */ -class SourceInfoWhiteboxTransform(val c: whitebox.Context) extends AutoSourceTransform { - import c.universe._ - - def noArg(): c.Tree = { - q"$thisObj.$doFuncTerm($implicitSourceInfo)" - } - - def thatArg(that: c.Tree): c.Tree = { - q"$thisObj.$doFuncTerm($that)($implicitSourceInfo)" - } -} diff --git a/coreMacros/src/main/scala/chisel3/internal/sourceinfo/SourceInfoTransform.scala b/coreMacros/src/main/scala/chisel3/internal/sourceinfo/SourceInfoTransform.scala new file mode 100644 index 00000000..82ad5b9e --- /dev/null +++ b/coreMacros/src/main/scala/chisel3/internal/sourceinfo/SourceInfoTransform.scala @@ -0,0 +1,156 @@ +// See LICENSE for license details. + +// This file transform macro definitions to explicitly add implicit source info to Chisel method +// calls. + +package Chisel.internal.sourceinfo + +import scala.language.experimental.macros +import scala.reflect.macros.blackbox.Context +import scala.reflect.macros.whitebox + + +/** Transforms a function call so that it can both provide implicit-style source information and + * have a chained apply call. Without macros, only one is possible, since having a implicit + * argument in the definition will cause the compiler to interpret a chained apply as an + * explicit implicit argument and give type errors. + * + * Instead of an implicit argument, the public-facing function no longer takes a SourceInfo at all. + * The macro transforms the public-facing function into a call to an internal function that takes + * an explicit SourceInfo by inserting an implicitly[SourceInfo] as the explicit argument. + */ +trait SourceInfoTransformMacro { + val c: Context + import c.universe._ + def thisObj = c.prefix.tree + def implicitSourceInfo = q"implicitly[_root_.Chisel.internal.sourceinfo.SourceInfo]" +} + +class WireTransform(val c: Context) extends SourceInfoTransformMacro { + import c.universe._ + def apply[T: c.WeakTypeTag](t: c.Tree): c.Tree = { + val tpe = weakTypeOf[T] + q"$thisObj.do_apply($t, null.asInstanceOf[$tpe])($implicitSourceInfo)" + } +} + +class UIntTransform(val c: Context) extends SourceInfoTransformMacro { + import c.universe._ + def bitset(off: c.Tree, dat: c.Tree): c.Tree = { + q"$thisObj.do_bitSet($off, $dat)($implicitSourceInfo)" + } +} + +// Module instantiation transform +class InstTransform(val c: Context) extends SourceInfoTransformMacro { + import c.universe._ + def apply[T: c.WeakTypeTag](bc: c.Tree): c.Tree = { + q"$thisObj.do_apply($bc)($implicitSourceInfo)" + } +} + +class MemTransform(val c: Context) extends SourceInfoTransformMacro { + import c.universe._ + def apply[T: c.WeakTypeTag](size: c.Tree, t: c.Tree): c.Tree = { + q"$thisObj.do_apply($size, $t)($implicitSourceInfo)" + } +} + +class RegTransform(val c: Context) extends SourceInfoTransformMacro { + import c.universe._ + def apply[T: c.WeakTypeTag](t: c.Tree): c.Tree = { + val tpe = weakTypeOf[T] + q"$thisObj.do_apply($t, null.asInstanceOf[$tpe], null.asInstanceOf[$tpe])($implicitSourceInfo)" + } +} + +class MuxTransform(val c: Context) extends SourceInfoTransformMacro { + import c.universe._ + def apply[T: c.WeakTypeTag](cond: c.Tree, con: c.Tree, alt: c.Tree): c.Tree = { + val tpe = weakTypeOf[T] + q"$thisObj.do_apply[$tpe]($cond, $con, $alt)($implicitSourceInfo)" + } +} + +class VecTransform(val c: Context) extends SourceInfoTransformMacro { + import c.universe._ + def apply_elts(elts: c.Tree): c.Tree = { + q"$thisObj.do_apply($elts)($implicitSourceInfo)" + } + def apply_elt0(elt0: c.Tree, elts: c.Tree*): c.Tree = { + q"$thisObj.do_apply($elt0, ..$elts)($implicitSourceInfo)" + } + def tabulate(n: c.Tree)(gen: c.Tree): c.Tree = { + q"$thisObj.do_tabulate($n)($gen)($implicitSourceInfo)" + } + def fill(n: c.Tree)(gen: c.Tree): c.Tree = { + q"$thisObj.do_fill($n)($gen)($implicitSourceInfo)" + } + def contains(x: c.Tree)(ev: c.Tree): c.Tree = { + q"$thisObj.do_contains($x)($implicitSourceInfo, $ev)" + } +} + +/** "Automatic" source information transform / insertion macros, which generate the function name + * based on the macro invocation (instead of explicitly writing out every transform). + */ +abstract class AutoSourceTransform extends SourceInfoTransformMacro { + import c.universe._ + /** Returns the TermName of the transformed function, which is the applied function name with do_ + * prepended. + */ + def doFuncTerm = { + val funcName = c.macroApplication match { + case q"$_.$funcName[..$_](...$_)" => funcName + case _ => throw new Exception(s"Chisel Internal Error: Could not resolve function name from macro application: ${showCode(c.macroApplication)}") + } + TermName("do_" + funcName) + } +} + +class SourceInfoTransform(val c: Context) extends AutoSourceTransform { + import c.universe._ + + def noArg(): c.Tree = { + q"$thisObj.$doFuncTerm($implicitSourceInfo)" + } + + def thatArg(that: c.Tree): c.Tree = { + q"$thisObj.$doFuncTerm($that)($implicitSourceInfo)" + } + + def nArg(n: c.Tree): c.Tree = { + q"$thisObj.$doFuncTerm($n)($implicitSourceInfo)" + } + + def pArg(p: c.Tree): c.Tree = { + q"$thisObj.$doFuncTerm($p)($implicitSourceInfo)" + } + + def inArg(in: c.Tree): c.Tree = { + q"$thisObj.$doFuncTerm($in)($implicitSourceInfo)" + } + + def xArg(x: c.Tree): c.Tree = { + q"$thisObj.$doFuncTerm($x)($implicitSourceInfo)" + } + + def xyArg(x: c.Tree, y: c.Tree): c.Tree = { + q"$thisObj.$doFuncTerm($x, $y)($implicitSourceInfo)" + } +} + +/** Special whitebox version of the blackbox SourceInfoTransform, used when fun things need to happen to satisfy the + * type system while preventing the use of macro overrides. + */ +class SourceInfoWhiteboxTransform(val c: whitebox.Context) extends AutoSourceTransform { + import c.universe._ + + def noArg(): c.Tree = { + q"$thisObj.$doFuncTerm($implicitSourceInfo)" + } + + def thatArg(that: c.Tree): c.Tree = { + q"$thisObj.$doFuncTerm($that)($implicitSourceInfo)" + } +} diff --git a/src/main/scala/Chisel/BitPat.scala b/src/main/scala/Chisel/BitPat.scala deleted file mode 100644 index 96206f63..00000000 --- a/src/main/scala/Chisel/BitPat.scala +++ /dev/null @@ -1,88 +0,0 @@ -// See LICENSE for license details. - -package Chisel - -import scala.language.experimental.macros - -import Chisel.internal.sourceinfo.{SourceInfo, SourceInfoTransform} - -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) - */ - 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 - */ - 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 === (that: UInt): Bool = macro SourceInfoTransform.thatArg - def =/= (that: UInt): Bool = macro SourceInfoTransform.thatArg - def != (that: UInt): Bool = macro SourceInfoTransform.thatArg - - def do_=== (that: UInt)(implicit sourceInfo: SourceInfo): Bool = UInt(value) === (that & UInt(mask)) - def do_=/= (that: UInt)(implicit sourceInfo: SourceInfo): Bool = !(this === that) - def do_!= (that: UInt)(implicit sourceInfo: SourceInfo): Bool = this =/= that -} diff --git a/src/main/scala/Chisel/Driver.scala b/src/main/scala/Chisel/Driver.scala deleted file mode 100644 index 02204684..00000000 --- a/src/main/scala/Chisel/Driver.scala +++ /dev/null @@ -1,132 +0,0 @@ -// See LICENSE for license details. - -package Chisel - -import scala.sys.process._ -import java.io._ - -import internal._ -import internal.firrtl._ - -trait BackendCompilationUtilities { - /** Create a temporary directory with the prefix name. Exists here because it doesn't in Java 6. - */ - def createTempDirectory(prefix: String): File = { - val temp = File.createTempFile(prefix, "") - if (!temp.delete()) { - throw new IOException(s"Unable to delete temp file '$temp'") - } - if (!temp.mkdir()) { - throw new IOException(s"Unable to create temp directory '$temp'") - } - temp - } - - def makeHarness(template: String => String, post: String)(f: File): File = { - val prefix = f.toString.split("/").last - val vf = new File(f.toString + post) - val w = new FileWriter(vf) - w.write(template(prefix)) - w.close() - vf - } - - def firrtlToVerilog(prefix: String, dir: File): ProcessBuilder = { - Process( - Seq("firrtl", - "-i", s"$prefix.fir", - "-o", s"$prefix.v", - "-X", "verilog"), - dir) - } - - /** Generates a Verilator invocation to convert Verilog sources to C++ - * simulation sources. - * - * The Verilator prefix will be V$dutFile, and running this will generate - * C++ sources and headers as well as a makefile to compile them. - * - * @param dutFile name of the DUT .v without the .v extension - * @param name of the top-level module in the design - * @param dir output directory - * @param vSources list of additional Verilog sources to compile - * @param cppHarness C++ testharness to compile/link against - */ - def verilogToCpp( - dutFile: String, - topModule: String, - dir: File, - vSources: Seq[File], - cppHarness: File - ): ProcessBuilder = { - val command = Seq("verilator", - "--cc", s"$dutFile.v") ++ - vSources.map(file => Seq("-v", file.toString)).flatten ++ - Seq("--assert", - "-Wno-fatal", - "-Wno-WIDTH", - "-Wno-STMTDLY", - "--trace", - "-O2", - "--top-module", topModule, - "+define+TOP_TYPE=V" + dutFile, - s"+define+PRINTF_COND=!$topModule.reset", - "-CFLAGS", - s"""-Wno-undefined-bool-conversion -O2 -DTOP_TYPE=V$dutFile -include V$dutFile.h""", - "-Mdir", dir.toString, - "--exe", cppHarness.toString) - System.out.println(s"${command.mkString(" ")}") // scalastyle:ignore regex - command - } - - def cppToExe(prefix: String, dir: File): ProcessBuilder = - Seq("make", "-C", dir.toString, "-j", "-f", s"V${prefix}.mk", s"V${prefix}") - - def executeExpectingFailure( - prefix: String, - dir: File, - assertionMsg: String = "Assertion failed"): Boolean = { - var triggered = false - val e = Process(s"./V${prefix}", dir) ! - ProcessLogger(line => { - triggered = triggered || line.contains(assertionMsg) - System.out.println(line) // scalastyle:ignore regex - }) - triggered - } - - def executeExpectingSuccess(prefix: String, dir: File): Boolean = { - !executeExpectingFailure(prefix, dir) - } -} - -object Driver extends BackendCompilationUtilities { - - /** Elaborates the Module specified in the gen function into a Circuit - * - * @param gen a function that creates a Module hierarchy - * @return the resulting Chisel IR in the form of a Circuit (TODO: Should be FIRRTL IR) - */ - def elaborate[T <: Module](gen: () => T): Circuit = Builder.build(Module(gen())) - - def emit[T <: Module](gen: () => T): String = Emitter.emit(elaborate(gen)) - - def dumpFirrtl(ir: Circuit, optName: Option[File]): File = { - val f = optName.getOrElse(new File(ir.name + ".fir")) - val w = new FileWriter(f) - w.write(Emitter.emit(ir)) - w.close() - f - } - - private var target_dir: Option[String] = None - def parseArgs(args: Array[String]): Unit = { - for (i <- 0 until args.size) { - if (args(i) == "--targetDir") { - target_dir = Some(args(i + 1)) - } - } - } - - def targetDir(): String = { target_dir getOrElse new File(".").getCanonicalPath } -} diff --git a/src/main/scala/Chisel/FileSystemUtilities.scala b/src/main/scala/Chisel/FileSystemUtilities.scala deleted file mode 100644 index 575ae138..00000000 --- a/src/main/scala/Chisel/FileSystemUtilities.scala +++ /dev/null @@ -1,10 +0,0 @@ -// See LICENSE for license details. - -package Chisel - -@deprecated("FileSystemUtilities doesn't exist in chisel3", "3.0.0") -trait FileSystemUtilities { - def createOutputFile(name: String): java.io.FileWriter = { - new java.io.FileWriter(Driver.targetDir + "/" + name) - } -} diff --git a/src/main/scala/Chisel/ImplicitConversions.scala b/src/main/scala/Chisel/ImplicitConversions.scala deleted file mode 100644 index 6a230022..00000000 --- a/src/main/scala/Chisel/ImplicitConversions.scala +++ /dev/null @@ -1,8 +0,0 @@ -// See LICENSE for license details. - -package Chisel - -object ImplicitConversions { - implicit def intToUInt(x: Int): UInt = UInt(x) - implicit def booleanToBool(x: Boolean): Bool = Bool(x) -} diff --git a/src/main/scala/Chisel/Main.scala b/src/main/scala/Chisel/Main.scala deleted file mode 100644 index a72debc3..00000000 --- a/src/main/scala/Chisel/Main.scala +++ /dev/null @@ -1,17 +0,0 @@ -// See LICENSE for license details. - -package Chisel - -import java.io.File - -@deprecated("chiselMain doesn't exist in Chisel3", "3.0") object chiselMain { - def apply[T <: Module](args: Array[String], gen: () => T): Unit = - Predef.assert(false, "No more chiselMain in Chisel3") - - def run[T <: Module] (args: Array[String], gen: () => T): Unit = { - val circuit = Driver.elaborate(gen) - Driver.parseArgs(args) - val output_file = new File(Driver.targetDir + "/" + circuit.name + ".fir") - Driver.dumpFirrtl(circuit, Option(output_file)) - } -} diff --git a/src/main/scala/Chisel/internal/firrtl/Emitter.scala b/src/main/scala/Chisel/internal/firrtl/Emitter.scala deleted file mode 100644 index 7ca3268a..00000000 --- a/src/main/scala/Chisel/internal/firrtl/Emitter.scala +++ /dev/null @@ -1,112 +0,0 @@ -// See LICENSE for license details. - -package Chisel.internal.firrtl -import Chisel._ -import Chisel.internal.sourceinfo.{NoSourceInfo, SourceLine} - -private[Chisel] object Emitter { - def emit(circuit: Circuit): String = new Emitter(circuit).toString -} - -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 = { - val firrtlLine = 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() - s"skip" - } - e.sourceInfo match { - case SourceLine(filename, line, col) => s"${firrtlLine} @[${filename} ${line}:${col}] " - case _: NoSourceInfo => firrtlLine - } - } - - // 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/src/main/scala/Chisel/package.scala b/src/main/scala/Chisel/package.scala deleted file mode 100644 index f05e8b5d..00000000 --- a/src/main/scala/Chisel/package.scala +++ /dev/null @@ -1,31 +0,0 @@ -package object Chisel { - import scala.language.experimental.macros - - import internal.firrtl.Width - import internal.sourceinfo.{SourceInfo, SourceInfoTransform} - - implicit class fromBigIntToLiteral(val x: BigInt) extends AnyVal { - def U: UInt = UInt(x, Width()) - def S: SInt = SInt(x, Width()) - } - implicit class fromIntToLiteral(val x: Int) extends AnyVal { - def U: UInt = UInt(BigInt(x), Width()) - def S: SInt = SInt(BigInt(x), Width()) - } - implicit class fromStringToLiteral(val x: String) extends AnyVal { - def U: UInt = UInt(x) - } - implicit class fromBooleanToLiteral(val x: Boolean) extends AnyVal { - def B: Bool = Bool(x) - } - - implicit class fromUIntToBitPatComparable(val x: UInt) extends AnyVal { - final def === (that: BitPat): Bool = macro SourceInfoTransform.thatArg - final def != (that: BitPat): Bool = macro SourceInfoTransform.thatArg - final def =/= (that: BitPat): Bool = macro SourceInfoTransform.thatArg - - def do_=== (that: BitPat)(implicit sourceInfo: SourceInfo): Bool = that === x - def do_!= (that: BitPat)(implicit sourceInfo: SourceInfo): Bool = that != x - def do_=/= (that: BitPat)(implicit sourceInfo: SourceInfo): Bool = that =/= x - } -} diff --git a/src/main/scala/Chisel/testers/BasicTester.scala b/src/main/scala/Chisel/testers/BasicTester.scala deleted file mode 100644 index b8c1494a..00000000 --- a/src/main/scala/Chisel/testers/BasicTester.scala +++ /dev/null @@ -1,38 +0,0 @@ -// See LICENSE for license details. - -package Chisel.testers -import Chisel._ - -import scala.language.experimental.macros - -import internal._ -import internal.Builder.pushCommand -import internal.firrtl._ -import internal.sourceinfo.SourceInfo - -class BasicTester extends Module { - // The testbench has no IOs, rather it should communicate using printf, assert, and stop. - val io = new Bundle() - - def popCount(n: Long): Int = n.toBinaryString.count(_=='1') - - /** Ends the test reporting success. - * - * 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. - */ - def stop()(implicit sourceInfo: SourceInfo) { - // TODO: rewrite this using library-style SourceInfo passing. - when (!reset) { - pushCommand(Stop(sourceInfo, Node(clock), 0)) - } - } - - /** The finish method provides a hook that subclasses of BasicTester can use to - * alter a circuit after their constructor has been called. - * For example, a specialized tester subclassing BasicTester could override finish in order to - * add flow control logic for a decoupled io port of a device under test - */ - def finish(): Unit = {} -} diff --git a/src/main/scala/Chisel/testers/TesterDriver.scala b/src/main/scala/Chisel/testers/TesterDriver.scala deleted file mode 100644 index a56bb8b7..00000000 --- a/src/main/scala/Chisel/testers/TesterDriver.scala +++ /dev/null @@ -1,68 +0,0 @@ -// See LICENSE for license details. - -package Chisel.testers -import Chisel._ -import scala.io.Source -import scala.sys.process._ -import java.io._ - -object TesterDriver extends BackendCompilationUtilities { - /** Copy the contents of a resource to a destination file. - */ - def copyResourceToFile(name: String, file: File) { - val in = getClass().getResourceAsStream(name) - if (in == null) { - throw new FileNotFoundException(s"Resource '$name'") - } - val out = new FileOutputStream(file) - Iterator.continually(in.read).takeWhile(-1 !=).foreach(out.write) - out.close() - } - - /** For use with modules that should successfully be elaborated by the - * frontend, and which can be turned into executables with assertions. */ - def execute(t: () => BasicTester, additionalVResources: Seq[String] = Seq()): Boolean = { - // Invoke the chisel compiler to get the circuit's IR - val circuit = Driver.elaborate(finishWrapper(t)) - - // Set up a bunch of file handlers based on a random temp filename, - // plus the quirks of Verilator's naming conventions - val target = circuit.name - - val path = createTempDirectory(target) - val fname = new File(path, target) - - // For now, dump the IR out to a file - Driver.dumpFirrtl(circuit, Some(new File(fname.toString + ".fir"))) - - // Copy CPP harness and other Verilog sources from resources into files - val cppHarness = new File(path, "top.cpp") - copyResourceToFile("/top.cpp", cppHarness) - val additionalVFiles = additionalVResources.map((name: String) => { - val mangledResourceName = name.replace("/", "_") - val out = new File(path, mangledResourceName) - copyResourceToFile(name, out) - out - }) - - // Use sys.Process to invoke a bunch of backend stuff, then run the resulting exe - if ((firrtlToVerilog(target, path) #&& - verilogToCpp(target, target, path, additionalVFiles, cppHarness) #&& - cppToExe(target, path)).! == 0) { - executeExpectingSuccess(target, path) - } else { - false - } - } - /** - * Calls the finish method of an BasicTester or a class that extends it. - * The finish method is a hook for code that augments the circuit built in the constructor. - */ - def finishWrapper(test: () => BasicTester): () => BasicTester = { - () => { - val tester = test() - tester.finish() - tester - } - } -} diff --git a/src/main/scala/Chisel/throwException.scala b/src/main/scala/Chisel/throwException.scala deleted file mode 100644 index 702884aa..00000000 --- a/src/main/scala/Chisel/throwException.scala +++ /dev/null @@ -1,12 +0,0 @@ -// See LICENSE for license details. - -package Chisel - -@deprecated("throwException doesn't exist in Chisel3", "3.0.0") -@throws(classOf[Exception]) -object throwException { - def apply(s: String, t: Throwable = null) = { - val xcpt = new Exception(s, t) - throw xcpt - } -} diff --git a/src/main/scala/Chisel/util/Arbiter.scala b/src/main/scala/Chisel/util/Arbiter.scala deleted file mode 100644 index 16ae9be5..00000000 --- a/src/main/scala/Chisel/util/Arbiter.scala +++ /dev/null @@ -1,117 +0,0 @@ -// See LICENSE for license details. - -/** Arbiters in all shapes and sizes. - */ - -package Chisel - -/** An I/O bundle for the Arbiter */ -class ArbiterIO[T <: Data](gen: T, n: Int) extends Bundle { - val in = Vec(n, Decoupled(gen)).flip - val out = Decoupled(gen) - val chosen = UInt(OUTPUT, log2Up(n)) -} - -/** Arbiter Control determining which producer has access */ -private object ArbiterCtrl -{ - def apply(request: Seq[Bool]): Seq[Bool] = request.length match { - case 0 => Seq() - case 1 => Seq(Bool(true)) - case _ => Bool(true) +: request.tail.init.scanLeft(request.head)(_ || _).map(!_) - } -} - -abstract class LockingArbiterLike[T <: Data](gen: T, n: Int, count: Int, needsLock: Option[T => Bool]) extends Module { - def grant: Seq[Bool] - def choice: UInt - val io = new ArbiterIO(gen, n) - - io.chosen := choice - io.out.valid := io.in(io.chosen).valid - io.out.bits := io.in(io.chosen).bits - - if (count > 1) { - val lockCount = Counter(count) - val lockIdx = Reg(UInt()) - val locked = lockCount.value =/= UInt(0) - val wantsLock = needsLock.map(_(io.out.bits)).getOrElse(Bool(true)) - - when (io.out.fire() && wantsLock) { - lockIdx := io.chosen - lockCount.inc() - } - - when (locked) { io.chosen := lockIdx } - for ((in, (g, i)) <- io.in zip grant.zipWithIndex) - in.ready := Mux(locked, lockIdx === UInt(i), g) && io.out.ready - } else { - for ((in, g) <- io.in zip grant) - in.ready := g && io.out.ready - } -} - -class LockingRRArbiter[T <: Data](gen: T, n: Int, count: Int, needsLock: Option[T => Bool] = None) - extends LockingArbiterLike[T](gen, n, count, needsLock) { - lazy val lastGrant = RegEnable(io.chosen, io.out.fire()) - lazy val grantMask = (0 until n).map(UInt(_) > lastGrant) - lazy val validMask = io.in zip grantMask map { case (in, g) => in.valid && g } - - override def grant: Seq[Bool] = { - val ctrl = ArbiterCtrl((0 until n).map(i => validMask(i)) ++ io.in.map(_.valid)) - (0 until n).map(i => ctrl(i) && grantMask(i) || ctrl(i + n)) - } - - override lazy val choice = Wire(init=UInt(n-1)) - for (i <- n-2 to 0 by -1) - when (io.in(i).valid) { choice := UInt(i) } - for (i <- n-1 to 1 by -1) - when (validMask(i)) { choice := UInt(i) } -} - -class LockingArbiter[T <: Data](gen: T, n: Int, count: Int, needsLock: Option[T => Bool] = None) - extends LockingArbiterLike[T](gen, n, count, needsLock) { - def grant: Seq[Bool] = ArbiterCtrl(io.in.map(_.valid)) - - override lazy val choice = Wire(init=UInt(n-1)) - for (i <- n-2 to 0 by -1) - when (io.in(i).valid) { choice := UInt(i) } -} - -/** Hardware module that is used to sequence n producers into 1 consumer. - Producers are chosen in round robin order. - - Example usage: - val arb = new RRArbiter(2, UInt()) - arb.io.in(0) <> producer0.io.out - arb.io.in(1) <> producer1.io.out - consumer.io.in <> arb.io.out - */ -class RRArbiter[T <: Data](gen:T, n: Int) extends LockingRRArbiter[T](gen, n, 1) - -/** Hardware module that is used to sequence n producers into 1 consumer. - Priority is given to lower producer - - Example usage: - val arb = Module(new Arbiter(2, UInt())) - arb.io.in(0) <> producer0.io.out - arb.io.in(1) <> producer1.io.out - consumer.io.in <> arb.io.out - */ -class Arbiter[T <: Data](gen: T, n: Int) extends Module { - val io = new ArbiterIO(gen, n) - - io.chosen := UInt(n-1) - io.out.bits := io.in(n-1).bits - for (i <- n-2 to 0 by -1) { - when (io.in(i).valid) { - io.chosen := UInt(i) - io.out.bits := io.in(i).bits - } - } - - val grant = ArbiterCtrl(io.in.map(_.valid)) - for ((in, g) <- io.in zip grant) - in.ready := g && io.out.ready - io.out.valid := !grant.last || io.in.last.valid -} diff --git a/src/main/scala/Chisel/util/Bitwise.scala b/src/main/scala/Chisel/util/Bitwise.scala deleted file mode 100644 index 239a295e..00000000 --- a/src/main/scala/Chisel/util/Bitwise.scala +++ /dev/null @@ -1,71 +0,0 @@ -// See LICENSE for license details. - -/** Miscellaneous circuit generators operating on bits. - */ - -package Chisel - -object FillInterleaved -{ - def apply(n: Int, in: UInt): UInt = apply(n, in.toBools) - def apply(n: Int, in: Seq[Bool]): UInt = Vec(in.map(Fill(n, _))).toBits -} - -/** Returns the number of bits set (i.e value is 1) in the input signal. - */ -object PopCount -{ - def apply(in: Iterable[Bool]): UInt = SeqUtils.count(in.toSeq) - def apply(in: Bits): UInt = apply((0 until in.getWidth).map(in(_))) -} - -/** Fill fans out a UInt to multiple copies */ -object Fill { - /** Fan out x n times */ - def apply(n: Int, x: UInt): UInt = { - n match { - case 0 => UInt(width=0) - case 1 => x - case y if n > 1 => - val p2 = Array.ofDim[UInt](log2Up(n + 1)) - p2(0) = x - for (i <- 1 until p2.length) - p2(i) = Cat(p2(i-1), p2(i-1)) - Cat((0 until log2Up(y + 1)).filter(i => (y & (1 << i)) != 0).map(p2(_))) - case _ => throw new IllegalArgumentException(s"n (=$n) must be nonnegative integer.") - } - } - /** Fan out x n times */ - def apply(n: Int, x: Bool): UInt = - if (n > 1) { - UInt(0,n) - x - } else { - apply(n, x: UInt) - } -} - -/** Litte/big bit endian convertion: reverse the order of the bits in a UInt. -*/ -object Reverse -{ - private def doit(in: UInt, length: Int): UInt = { - if (length == 1) { - in - } else if (isPow2(length) && length >= 8 && length <= 64) { - // This esoterica improves simulation performance - var res = in - var shift = length >> 1 - var mask = UInt((BigInt(1) << length) - 1, length) - do { - mask = mask ^ (mask(length-shift-1,0) << shift) - res = ((res >> shift) & mask) | ((res(length-shift-1,0) << shift) & ~mask) - shift = shift >> 1 - } while (shift > 0) - res - } else { - val half = (1 << log2Up(length))/2 - Cat(doit(in(half-1,0), half), doit(in(length-1,half), length-half)) - } - } - def apply(in: UInt): UInt = doit(in, in.getWidth) -} diff --git a/src/main/scala/Chisel/util/Cat.scala b/src/main/scala/Chisel/util/Cat.scala deleted file mode 100644 index dd706e62..00000000 --- a/src/main/scala/Chisel/util/Cat.scala +++ /dev/null @@ -1,18 +0,0 @@ -// See LICENSE for license details. - -package Chisel - -object Cat { - /** Combine data elements together - * @param a Data to combine with - * @param r any number of other Data elements to be combined in order - * @return A UInt which is all of the bits combined together - */ - def apply[T <: Bits](a: T, r: T*): UInt = apply(a :: r.toList) - - /** Combine data elements together - * @param r any number of other Data elements to be combined in order - * @return A UInt which is all of the bits combined together - */ - def apply[T <: Bits](r: Seq[T]): UInt = SeqUtils.asUInt(r.reverse) -} diff --git a/src/main/scala/Chisel/util/CircuitMath.scala b/src/main/scala/Chisel/util/CircuitMath.scala deleted file mode 100644 index 06cab903..00000000 --- a/src/main/scala/Chisel/util/CircuitMath.scala +++ /dev/null @@ -1,26 +0,0 @@ -// See LICENSE for license details. - -/** Circuit-land math operations. - */ - -package Chisel - -/** Compute Log2 with truncation of a UInt in hardware using a Mux Tree - * An alternative interpretation is it computes the minimum number of bits needed to represent x - * @example - * {{{ data_out := Log2(data_in) }}} - * @note Truncation is used so Log2(UInt(12412)) = 13*/ -object Log2 { - /** Compute the Log2 on the least significant n bits of x */ - def apply(x: Bits, width: Int): UInt = { - if (width < 2) { - UInt(0) - } else if (width == 2) { - x(1) - } else { - Mux(x(width-1), UInt(width-1), apply(x, width-1)) - } - } - - def apply(x: Bits): UInt = apply(x, x.getWidth) -} diff --git a/src/main/scala/Chisel/util/Conditional.scala b/src/main/scala/Chisel/util/Conditional.scala deleted file mode 100644 index 9cab25ef..00000000 --- a/src/main/scala/Chisel/util/Conditional.scala +++ /dev/null @@ -1,69 +0,0 @@ -// See LICENSE for license details. - -/** Conditional blocks. - */ - -package Chisel - -import scala.language.reflectiveCalls -import scala.language.experimental.macros -import scala.reflect.runtime.universe._ -import scala.reflect.macros.blackbox._ - -/** This is identical to [[Chisel.when when]] with the condition inverted */ -object unless { // scalastyle:ignore object.name - def apply(c: Bool)(block: => Unit) { - when (!c) { block } - } -} - -class SwitchContext[T <: Bits](cond: T) { - def is(v: Iterable[T])(block: => Unit) { - if (!v.isEmpty) when (v.map(_.asUInt === cond.asUInt).reduce(_||_)) { block } - } - def is(v: T)(block: => Unit) { is(Seq(v))(block) } - def is(v: T, vr: T*)(block: => Unit) { is(v :: vr.toList)(block) } -} - -/** An object for separate cases in [[Chisel.switch switch]] - * It is equivalent to a [[Chisel.when$ when]] block comparing to the condition - * Use outside of a switch statement is illegal */ -object is { // scalastyle:ignore object.name - // Begin deprecation of non-type-parameterized is statements. - def apply(v: Iterable[Bits])(block: => Unit) { - require(false, "The 'is' keyword may not be used outside of a switch.") - } - - def apply(v: Bits)(block: => Unit) { - require(false, "The 'is' keyword may not be used outside of a switch.") - } - - def apply(v: Bits, vr: Bits*)(block: => Unit) { - require(false, "The 'is' keyword may not be used outside of a switch.") - } -} - -/** Conditional logic to form a switch block - * @example - * {{{ ... // default values here - * switch ( myState ) { - * is( state1 ) { - * ... // some logic here - * } - * is( state2 ) { - * ... // some logic here - * } - * } }}}*/ -object switch { // scalastyle:ignore object.name - def apply[T <: Bits](cond: T)(x: => Unit): Unit = macro impl - def impl(c: Context)(cond: c.Tree)(x: c.Tree): c.Tree = { import c.universe._ - val sc = c.universe.internal.reificationSupport.freshTermName("sc") - def extractIsStatement(tree: Tree): List[c.universe.Tree] = tree match { - case q"Chisel.is.apply( ..$params )( ..$body )" => List(q"$sc.is( ..$params )( ..$body )") - case b => throw new Exception(s"Cannot include blocks that do not begin with is() in switch.") - } - val q"..$body" = x - val ises = body.flatMap(extractIsStatement(_)) - q"""{ val $sc = new SwitchContext($cond); ..$ises }""" - } -} diff --git a/src/main/scala/Chisel/util/Counter.scala b/src/main/scala/Chisel/util/Counter.scala deleted file mode 100644 index 872e830a..00000000 --- a/src/main/scala/Chisel/util/Counter.scala +++ /dev/null @@ -1,44 +0,0 @@ -// See LICENSE for license details. - -package Chisel - -/** A counter module - * @param n number of counts before the counter resets (or one more than the - * maximum output value of the counter), need not be a power of two - */ -class Counter(val n: Int) { - require(n >= 0) - val value = if (n > 1) Reg(init=UInt(0, log2Up(n))) else UInt(0) - /** Increment the counter, returning whether the counter currently is at the - * maximum and will wrap. The incremented value is registered and will be - * visible on the next cycle. - */ - def inc(): Bool = { - if (n > 1) { - val wrap = value === UInt(n-1) - value := value + UInt(1) - if (!isPow2(n)) { - when (wrap) { value := UInt(0) } - } - wrap - } else { - Bool(true) - } - } -} - -/** Counter Object - * Example Usage: - * {{{ val countOn = Bool(true) // increment counter every clock cycle - * val myCounter = Counter(countOn, n) - * when ( myCounter.value === UInt(3) ) { ... } }}}*/ -object Counter -{ - def apply(n: Int): Counter = new Counter(n) - def apply(cond: Bool, n: Int): (UInt, Bool) = { - val c = new Counter(n) - var wrap: Bool = null - when (cond) { wrap = c.inc() } - (c.value, cond && wrap) - } -} diff --git a/src/main/scala/Chisel/util/Decoupled.scala b/src/main/scala/Chisel/util/Decoupled.scala deleted file mode 100644 index 8e045855..00000000 --- a/src/main/scala/Chisel/util/Decoupled.scala +++ /dev/null @@ -1,183 +0,0 @@ -// See LICENSE for license details. - -/** Wrappers for ready-valid (Decoupled) interfaces and associated circuit generators using them. - */ - -package Chisel - -/** An I/O Bundle with simple handshaking using valid and ready signals for data 'bits'*/ -class DecoupledIO[+T <: Data](gen: T) extends Bundle -{ - val ready = Bool(INPUT) - val valid = Bool(OUTPUT) - val bits = gen.cloneType.asOutput - def fire(dummy: Int = 0): Bool = ready && valid - override def cloneType: this.type = new DecoupledIO(gen).asInstanceOf[this.type] -} - -/** Adds a ready-valid handshaking protocol to any interface. - * The standard used is that the consumer uses the flipped interface. - */ -object Decoupled { - def apply[T <: Data](gen: T): DecoupledIO[T] = new DecoupledIO(gen) -} - -/** An I/O bundle for enqueuing data with valid/ready handshaking - * Initialization must be handled, if necessary, by the parent circuit - */ -class EnqIO[T <: Data](gen: T) extends DecoupledIO(gen) -{ - /** push dat onto the output bits of this interface to let the consumer know it has happened. - * @param dat the values to assign to bits. - * @return dat. - */ - def enq(dat: T): T = { valid := Bool(true); bits := dat; dat } - - /** Initialize this Bundle. Valid is set to false, and all bits are set to zero. - * NOTE: This method of initialization is still being discussed and could change in the - * future. - */ - def init(): Unit = { - valid := Bool(false) - for (io <- bits.flatten) - io := UInt(0) - } - override def cloneType: this.type = { new EnqIO(gen).asInstanceOf[this.type]; } -} - -/** An I/O bundle for dequeuing data with valid/ready handshaking. - * Initialization must be handled, if necessary, by the parent circuit - */ -class DeqIO[T <: Data](gen: T) extends DecoupledIO(gen) with Flipped -{ - /** Assert ready on this port and return the associated data bits. - * This is typically used when valid has been asserted by the producer side. - * @param b ignored - * @return the data for this device, - */ - def deq(b: Boolean = false): T = { ready := Bool(true); bits } - - /** Initialize this Bundle. - * NOTE: This method of initialization is still being discussed and could change in the - * future. - */ - def init(): Unit = { - ready := Bool(false) - } - override def cloneType: this.type = { new DeqIO(gen).asInstanceOf[this.type]; } -} - -/** An I/O bundle for dequeuing data with valid/ready handshaking */ -class DecoupledIOC[+T <: Data](gen: T) extends Bundle -{ - val ready = Bool(INPUT) - val valid = Bool(OUTPUT) - val bits = gen.cloneType.asOutput -} - -/** An I/O Bundle for Queues - * @param gen The type of data to queue - * @param entries The max number of entries in the queue */ -class QueueIO[T <: Data](gen: T, entries: Int) extends Bundle -{ - /** I/O to enqueue data, is [[Chisel.DecoupledIO]] flipped */ - val enq = Decoupled(gen.cloneType).flip() - /** I/O to enqueue data, is [[Chisel.DecoupledIO]]*/ - val deq = Decoupled(gen.cloneType) - /** The current amount of data in the queue */ - val count = UInt(OUTPUT, log2Up(entries + 1)) -} - -/** A hardware module implementing a Queue - * @param gen The type of data to queue - * @param entries The max number of entries in the queue - * @param pipe True if a single entry queue can run at full throughput (like a pipeline). The ''ready'' signals are - * combinationally coupled. - * @param flow True if the inputs can be consumed on the same cycle (the inputs "flow" through the queue immediately). - * The ''valid'' signals are coupled. - * - * Example usage: - * {{{ val q = new Queue(UInt(), 16) - * q.io.enq <> producer.io.out - * consumer.io.in <> q.io.deq }}} - */ -class Queue[T <: Data](gen: T, val entries: Int, - pipe: Boolean = false, - flow: Boolean = false, - override_reset: Option[Bool] = None) -extends Module(override_reset=override_reset) { - def this(gen: T, entries: Int, pipe: Boolean, flow: Boolean, _reset: Bool) = - this(gen, entries, pipe, flow, Some(_reset)) - - val io = new QueueIO(gen, entries) - - val ram = Mem(entries, gen) - val enq_ptr = Counter(entries) - val deq_ptr = Counter(entries) - val maybe_full = Reg(init=Bool(false)) - - val ptr_match = enq_ptr.value === deq_ptr.value - val empty = ptr_match && !maybe_full - val full = ptr_match && maybe_full - val do_enq = Wire(init=io.enq.fire()) - val do_deq = Wire(init=io.deq.fire()) - - when (do_enq) { - ram(enq_ptr.value) := io.enq.bits - enq_ptr.inc() - } - when (do_deq) { - deq_ptr.inc() - } - when (do_enq != do_deq) { - maybe_full := do_enq - } - - io.deq.valid := !empty - io.enq.ready := !full - io.deq.bits := ram(deq_ptr.value) - - if (flow) { - when (io.enq.valid) { io.deq.valid := Bool(true) } - when (empty) { - io.deq.bits := io.enq.bits - do_deq := Bool(false) - when (io.deq.ready) { do_enq := Bool(false) } - } - } - - if (pipe) { - when (io.deq.ready) { io.enq.ready := Bool(true) } - } - - val ptr_diff = enq_ptr.value - deq_ptr.value - if (isPow2(entries)) { - io.count := Cat(maybe_full && ptr_match, ptr_diff) - } else { - io.count := Mux(ptr_match, - Mux(maybe_full, - UInt(entries), UInt(0)), - Mux(deq_ptr.value > enq_ptr.value, - UInt(entries) + ptr_diff, ptr_diff)) - } -} - -/** Generic hardware queue. Required parameter entries controls - the depth of the queues. The width of the queue is determined - from the inputs. - - Example usage: - {{{ val q = Queue(Decoupled(UInt()), 16) - q.io.enq <> producer.io.out - consumer.io.in <> q.io.deq }}} - */ -object Queue -{ - def apply[T <: Data](enq: DecoupledIO[T], entries: Int = 2, pipe: Boolean = false): DecoupledIO[T] = { - val q = Module(new Queue(enq.bits.cloneType, entries, pipe)) - q.io.enq.valid := enq.valid // not using <> so that override is allowed - q.io.enq.bits := enq.bits - enq.ready := q.io.enq.ready - TransitName(q.io.deq, q) - } -} diff --git a/src/main/scala/Chisel/util/Enum.scala b/src/main/scala/Chisel/util/Enum.scala deleted file mode 100644 index 20057197..00000000 --- a/src/main/scala/Chisel/util/Enum.scala +++ /dev/null @@ -1,21 +0,0 @@ -// See LICENSE for license details. - -/** Enum generators, allowing circuit constants to have more meaningful names. - */ - -package Chisel - -object Enum { - /** Returns a sequence of Bits subtypes with values from 0 until n. Helper method. */ - private def createValues[T <: Bits](nodeType: T, n: Int): Seq[T] = - (0 until n).map(x => nodeType.fromInt(x, log2Up(n))) - - /** create n enum values of given type */ - def apply[T <: Bits](nodeType: T, n: Int): List[T] = createValues(nodeType, n).toList - - /** create enum values of given type and names */ - def apply[T <: Bits](nodeType: T, l: Symbol *): Map[Symbol, T] = (l zip createValues(nodeType, l.length)).toMap - - /** create enum values of given type and names */ - def apply[T <: Bits](nodeType: T, l: List[Symbol]): Map[Symbol, T] = (l zip createValues(nodeType, l.length)).toMap -} diff --git a/src/main/scala/Chisel/util/LFSR.scala b/src/main/scala/Chisel/util/LFSR.scala deleted file mode 100644 index 839b1d1f..00000000 --- a/src/main/scala/Chisel/util/LFSR.scala +++ /dev/null @@ -1,22 +0,0 @@ -// See LICENSE for license details. - -/** LFSRs in all shapes and sizes. - */ - -package Chisel - -// scalastyle:off magic.number -/** linear feedback shift register - */ -object LFSR16 -{ - def apply(increment: Bool = Bool(true)): UInt = - { - val width = 16 - val lfsr = Reg(init=UInt(1, width)) - when (increment) { lfsr := Cat(lfsr(0)^lfsr(2)^lfsr(3)^lfsr(5), lfsr(width-1,1)) } - lfsr - } -} -// scalastyle:on magic.number - diff --git a/src/main/scala/Chisel/util/Lookup.scala b/src/main/scala/Chisel/util/Lookup.scala deleted file mode 100644 index 54922fc4..00000000 --- a/src/main/scala/Chisel/util/Lookup.scala +++ /dev/null @@ -1,17 +0,0 @@ -// See LICENSE for license details. - -package Chisel - -object ListLookup { - def apply[T <: Data](addr: UInt, default: List[T], mapping: Array[(BitPat, List[T])]): List[T] = { - val map = mapping.map(m => (m._1 === addr, m._2)) - default.zipWithIndex map { case (d, i) => - map.foldRight(d)((m, n) => Mux(m._1, m._2(i), n)) - } - } -} - -object Lookup { - def apply[T <: Bits](addr: UInt, default: T, mapping: Seq[(BitPat, T)]): T = - ListLookup(addr, List(default), mapping.map(m => (m._1, List(m._2))).toArray).head -} diff --git a/src/main/scala/Chisel/util/Math.scala b/src/main/scala/Chisel/util/Math.scala deleted file mode 100644 index 5f8212d8..00000000 --- a/src/main/scala/Chisel/util/Math.scala +++ /dev/null @@ -1,42 +0,0 @@ -// See LICENSE for license details. - -/** Scala-land math helper functions, like logs. - */ - -package Chisel - -/** Compute the log2 rounded up with min value of 1 */ -object log2Up { - def apply(in: BigInt): Int = { - require(in >= 0) - 1 max (in-1).bitLength - } - def apply(in: Int): Int = apply(BigInt(in)) -} - -/** Compute the log2 rounded up */ -object log2Ceil { - def apply(in: BigInt): Int = { - require(in > 0) - (in-1).bitLength - } - def apply(in: Int): Int = apply(BigInt(in)) -} - -/** Compute the log2 rounded down with min value of 1 */ -object log2Down { - def apply(in: BigInt): Int = log2Up(in) - (if (isPow2(in)) 0 else 1) - def apply(in: Int): Int = apply(BigInt(in)) -} - -/** Compute the log2 rounded down */ -object log2Floor { - def apply(in: BigInt): Int = log2Ceil(in) - (if (isPow2(in)) 0 else 1) - def apply(in: Int): Int = apply(BigInt(in)) -} - -/** Check if an Integer is a power of 2 */ -object isPow2 { - def apply(in: BigInt): Boolean = in > 0 && ((in & (in-1)) == 0) - def apply(in: Int): Boolean = apply(BigInt(in)) -} diff --git a/src/main/scala/Chisel/util/Mux.scala b/src/main/scala/Chisel/util/Mux.scala deleted file mode 100644 index 9d92321a..00000000 --- a/src/main/scala/Chisel/util/Mux.scala +++ /dev/null @@ -1,61 +0,0 @@ -// See LICENSE for license details. - -/** Mux circuit generators. - */ - -package Chisel - -/** Builds a Mux tree out of the input signal vector using a one hot encoded - select signal. Returns the output of the Mux tree. - */ -object Mux1H -{ - def apply[T <: Data](sel: Seq[Bool], in: Seq[T]): T = - apply(sel zip in) - def apply[T <: Data](in: Iterable[(Bool, T)]): T = SeqUtils.oneHotMux(in) - def apply[T <: Data](sel: UInt, in: Seq[T]): T = - apply((0 until in.size).map(sel(_)), in) - def apply(sel: UInt, in: UInt): Bool = (sel & in).orR -} - -/** Builds a Mux tree under the assumption that multiple select signals - can be enabled. Priority is given to the first select signal. - - Returns the output of the Mux tree. - */ -object PriorityMux -{ - def apply[T <: Data](in: Seq[(Bool, T)]): T = SeqUtils.priorityMux(in) - def apply[T <: Data](sel: Seq[Bool], in: Seq[T]): T = apply(sel zip in) - def apply[T <: Data](sel: Bits, in: Seq[T]): T = apply((0 until in.size).map(sel(_)), in) -} - -/** MuxLookup creates a cascade of n Muxs to search for a key value */ -object MuxLookup { - /** @param key a key to search for - * @param default a default value if nothing is found - * @param mapping a sequence to search of keys and values - * @return the value found or the default if not - */ - def apply[S <: UInt, T <: Bits] (key: S, default: T, mapping: Seq[(S, T)]): T = { - var res = default - for ((k, v) <- mapping.reverse) - res = Mux(k === key, v, res) - res - } - -} - -/** MuxCase returns the first value that is enabled in a map of values */ -object MuxCase { - /** @param default the default value if none are enabled - * @param mapping a set of data values with associated enables - * @return the first value in mapping that is enabled */ - def apply[T <: Bits] (default: T, mapping: Seq[(Bool, T)]): T = { - var res = default - for ((t, v) <- mapping.reverse){ - res = Mux(t, v, res) - } - res - } -} diff --git a/src/main/scala/Chisel/util/OneHot.scala b/src/main/scala/Chisel/util/OneHot.scala deleted file mode 100644 index 73f27403..00000000 --- a/src/main/scala/Chisel/util/OneHot.scala +++ /dev/null @@ -1,62 +0,0 @@ -// See LICENSE for license details. - -/** Circuit generators for working with one-hot representations. - */ - -package Chisel - -/** Converts from One Hot Encoding to a UInt indicating which bit is active - * This is the inverse of [[Chisel.UIntToOH UIntToOH]]*/ -object OHToUInt { - def apply(in: Seq[Bool]): UInt = apply(Vec(in)) - def apply(in: Vec[Bool]): UInt = apply(in.toBits, in.size) - def apply(in: Bits): UInt = apply(in, in.getWidth) - - def apply(in: Bits, width: Int): UInt = { - if (width <= 2) { - Log2(in, width) - } else { - val mid = 1 << (log2Up(width)-1) - val hi = in(width-1, mid) - val lo = in(mid-1, 0) - Cat(hi.orR, apply(hi | lo, mid)) - } - } -} - -/** @return the bit position of the trailing 1 in the input vector - * with the assumption that multiple bits of the input bit vector can be set - * @example {{{ data_out := PriorityEncoder(data_in) }}} - */ -object PriorityEncoder { - def apply(in: Seq[Bool]): UInt = PriorityMux(in, (0 until in.size).map(UInt(_))) - def apply(in: Bits): UInt = apply(in.toBools) -} - -/** Returns the one hot encoding of the input UInt. - */ -object UIntToOH -{ - def apply(in: UInt, width: Int = -1): UInt = - if (width == -1) { - UInt(1) << in - } else { - (UInt(1) << in(log2Up(width)-1,0))(width-1,0) - } -} - -/** Returns a bit vector in which only the least-significant 1 bit in - the input vector, if any, is set. - */ -object PriorityEncoderOH -{ - private def encode(in: Seq[Bool]): UInt = { - val outs = Seq.tabulate(in.size)(i => UInt(BigInt(1) << i, in.size)) - PriorityMux(in :+ Bool(true), outs :+ UInt(0, in.size)) - } - def apply(in: Seq[Bool]): Seq[Bool] = { - val enc = encode(in) - Seq.tabulate(in.size)(enc(_)) - } - def apply(in: Bits): UInt = encode((0 until in.getWidth).map(i => in(i))) -} diff --git a/src/main/scala/Chisel/util/Reg.scala b/src/main/scala/Chisel/util/Reg.scala deleted file mode 100644 index 6584a4bf..00000000 --- a/src/main/scala/Chisel/util/Reg.scala +++ /dev/null @@ -1,55 +0,0 @@ -// See LICENSE for license details. - -/** Variations and helpers for registers. - */ - -package Chisel - -object RegNext { - - def apply[T <: Data](next: T): T = Reg[T](null.asInstanceOf[T], next, null.asInstanceOf[T]) - - def apply[T <: Data](next: T, init: T): T = Reg[T](null.asInstanceOf[T], next, init) - -} - -object RegInit { - - def apply[T <: Data](init: T): T = Reg[T](null.asInstanceOf[T], null.asInstanceOf[T], init) - -} - -/** A register with an Enable signal */ -object RegEnable -{ - def apply[T <: Data](updateData: T, enable: Bool): T = { - val r = Reg(updateData) - when (enable) { r := updateData } - r - } - def apply[T <: Data](updateData: T, resetData: T, enable: Bool): T = { - val r = RegInit(resetData) - when (enable) { r := updateData } - r - } -} - -/** Returns the n-cycle delayed version of the input signal. - */ -object ShiftRegister -{ - /** @param in input to delay - * @param n number of cycles to delay - * @param en enable the shift */ - def apply[T <: Data](in: T, n: Int, en: Bool = Bool(true)): T = - { - // The order of tests reflects the expected use cases. - if (n == 1) { - RegEnable(in, en) - } else if (n != 0) { - RegNext(apply(in, n-1, en)) - } else { - in - } - } -} diff --git a/src/main/scala/Chisel/util/TransitName.scala b/src/main/scala/Chisel/util/TransitName.scala deleted file mode 100644 index ec5a11cc..00000000 --- a/src/main/scala/Chisel/util/TransitName.scala +++ /dev/null @@ -1,21 +0,0 @@ -package Chisel - -import internal.HasId - -object TransitName { - // The purpose of this is to allow a library to 'move' a name call to a more - // appropriate place. - // For example, a library factory function may create a module and return - // the io. The only user-exposed field is that given IO, which can't use - // any name supplied by the user. This can add a hook so that the supplied - // name then names the Module. - // See Queue companion object for working example - def apply[T<:HasId](from: T, to: HasId): T = { - from.addPostnameHook((given_name: String) => {to.suggestName(given_name)}) - from - } - def withSuffix[T<:HasId](suffix: String)(from: T, to: HasId): T = { - from.addPostnameHook((given_name: String) => {to.suggestName(given_name+suffix)}) - from - } -} diff --git a/src/main/scala/Chisel/util/Valid.scala b/src/main/scala/Chisel/util/Valid.scala deleted file mode 100644 index 9e2202bb..00000000 --- a/src/main/scala/Chisel/util/Valid.scala +++ /dev/null @@ -1,59 +0,0 @@ -// See LICENSE for license details. - -/** Wrappers for valid interfaces and associated circuit generators using them. - */ - -package Chisel - -/** An I/O Bundle containing data and a signal determining if it is valid */ -class ValidIO[+T <: Data](gen2: T) extends Bundle -{ - val valid = Bool(OUTPUT) - val bits = gen2.cloneType.asOutput - def fire(dummy: Int = 0): Bool = valid - override def cloneType: this.type = new ValidIO(gen2).asInstanceOf[this.type] -} - -/** Adds a valid protocol to any interface. The standard used is - that the consumer uses the flipped interface. -*/ -object Valid { - def apply[T <: Data](gen: T): ValidIO[T] = new ValidIO(gen) -} - -/** A hardware module that delays data coming down the pipeline - by the number of cycles set by the latency parameter. Functionality - is similar to ShiftRegister but this exposes a Pipe interface. - - Example usage: - val pipe = new Pipe(UInt()) - pipe.io.enq <> produce.io.out - consumer.io.in <> pipe.io.deq - */ -object Pipe -{ - def apply[T <: Data](enqValid: Bool, enqBits: T, latency: Int): ValidIO[T] = { - if (latency == 0) { - val out = Wire(Valid(enqBits)) - out.valid <> enqValid - out.bits <> enqBits - out - } else { - val v = Reg(Bool(), next=enqValid, init=Bool(false)) - val b = RegEnable(enqBits, enqValid) - apply(v, b, latency-1) - } - } - def apply[T <: Data](enqValid: Bool, enqBits: T): ValidIO[T] = apply(enqValid, enqBits, 1) - def apply[T <: Data](enq: ValidIO[T], latency: Int = 1): ValidIO[T] = apply(enq.valid, enq.bits, latency) -} - -class Pipe[T <: Data](gen: T, latency: Int = 1) extends Module -{ - val io = new Bundle { - val enq = Valid(gen).flip - val deq = Valid(gen) - } - - io.deq <> Pipe(io.enq, latency) -} diff --git a/src/main/scala/chisel3/Driver.scala b/src/main/scala/chisel3/Driver.scala new file mode 100644 index 00000000..02204684 --- /dev/null +++ b/src/main/scala/chisel3/Driver.scala @@ -0,0 +1,132 @@ +// See LICENSE for license details. + +package Chisel + +import scala.sys.process._ +import java.io._ + +import internal._ +import internal.firrtl._ + +trait BackendCompilationUtilities { + /** Create a temporary directory with the prefix name. Exists here because it doesn't in Java 6. + */ + def createTempDirectory(prefix: String): File = { + val temp = File.createTempFile(prefix, "") + if (!temp.delete()) { + throw new IOException(s"Unable to delete temp file '$temp'") + } + if (!temp.mkdir()) { + throw new IOException(s"Unable to create temp directory '$temp'") + } + temp + } + + def makeHarness(template: String => String, post: String)(f: File): File = { + val prefix = f.toString.split("/").last + val vf = new File(f.toString + post) + val w = new FileWriter(vf) + w.write(template(prefix)) + w.close() + vf + } + + def firrtlToVerilog(prefix: String, dir: File): ProcessBuilder = { + Process( + Seq("firrtl", + "-i", s"$prefix.fir", + "-o", s"$prefix.v", + "-X", "verilog"), + dir) + } + + /** Generates a Verilator invocation to convert Verilog sources to C++ + * simulation sources. + * + * The Verilator prefix will be V$dutFile, and running this will generate + * C++ sources and headers as well as a makefile to compile them. + * + * @param dutFile name of the DUT .v without the .v extension + * @param name of the top-level module in the design + * @param dir output directory + * @param vSources list of additional Verilog sources to compile + * @param cppHarness C++ testharness to compile/link against + */ + def verilogToCpp( + dutFile: String, + topModule: String, + dir: File, + vSources: Seq[File], + cppHarness: File + ): ProcessBuilder = { + val command = Seq("verilator", + "--cc", s"$dutFile.v") ++ + vSources.map(file => Seq("-v", file.toString)).flatten ++ + Seq("--assert", + "-Wno-fatal", + "-Wno-WIDTH", + "-Wno-STMTDLY", + "--trace", + "-O2", + "--top-module", topModule, + "+define+TOP_TYPE=V" + dutFile, + s"+define+PRINTF_COND=!$topModule.reset", + "-CFLAGS", + s"""-Wno-undefined-bool-conversion -O2 -DTOP_TYPE=V$dutFile -include V$dutFile.h""", + "-Mdir", dir.toString, + "--exe", cppHarness.toString) + System.out.println(s"${command.mkString(" ")}") // scalastyle:ignore regex + command + } + + def cppToExe(prefix: String, dir: File): ProcessBuilder = + Seq("make", "-C", dir.toString, "-j", "-f", s"V${prefix}.mk", s"V${prefix}") + + def executeExpectingFailure( + prefix: String, + dir: File, + assertionMsg: String = "Assertion failed"): Boolean = { + var triggered = false + val e = Process(s"./V${prefix}", dir) ! + ProcessLogger(line => { + triggered = triggered || line.contains(assertionMsg) + System.out.println(line) // scalastyle:ignore regex + }) + triggered + } + + def executeExpectingSuccess(prefix: String, dir: File): Boolean = { + !executeExpectingFailure(prefix, dir) + } +} + +object Driver extends BackendCompilationUtilities { + + /** Elaborates the Module specified in the gen function into a Circuit + * + * @param gen a function that creates a Module hierarchy + * @return the resulting Chisel IR in the form of a Circuit (TODO: Should be FIRRTL IR) + */ + def elaborate[T <: Module](gen: () => T): Circuit = Builder.build(Module(gen())) + + def emit[T <: Module](gen: () => T): String = Emitter.emit(elaborate(gen)) + + def dumpFirrtl(ir: Circuit, optName: Option[File]): File = { + val f = optName.getOrElse(new File(ir.name + ".fir")) + val w = new FileWriter(f) + w.write(Emitter.emit(ir)) + w.close() + f + } + + private var target_dir: Option[String] = None + def parseArgs(args: Array[String]): Unit = { + for (i <- 0 until args.size) { + if (args(i) == "--targetDir") { + target_dir = Some(args(i + 1)) + } + } + } + + def targetDir(): String = { target_dir getOrElse new File(".").getCanonicalPath } +} diff --git a/src/main/scala/chisel3/compatibility/FileSystemUtilities.scala b/src/main/scala/chisel3/compatibility/FileSystemUtilities.scala new file mode 100644 index 00000000..575ae138 --- /dev/null +++ b/src/main/scala/chisel3/compatibility/FileSystemUtilities.scala @@ -0,0 +1,10 @@ +// See LICENSE for license details. + +package Chisel + +@deprecated("FileSystemUtilities doesn't exist in chisel3", "3.0.0") +trait FileSystemUtilities { + def createOutputFile(name: String): java.io.FileWriter = { + new java.io.FileWriter(Driver.targetDir + "/" + name) + } +} diff --git a/src/main/scala/chisel3/compatibility/Main.scala b/src/main/scala/chisel3/compatibility/Main.scala new file mode 100644 index 00000000..a72debc3 --- /dev/null +++ b/src/main/scala/chisel3/compatibility/Main.scala @@ -0,0 +1,17 @@ +// See LICENSE for license details. + +package Chisel + +import java.io.File + +@deprecated("chiselMain doesn't exist in Chisel3", "3.0") object chiselMain { + def apply[T <: Module](args: Array[String], gen: () => T): Unit = + Predef.assert(false, "No more chiselMain in Chisel3") + + def run[T <: Module] (args: Array[String], gen: () => T): Unit = { + val circuit = Driver.elaborate(gen) + Driver.parseArgs(args) + val output_file = new File(Driver.targetDir + "/" + circuit.name + ".fir") + Driver.dumpFirrtl(circuit, Option(output_file)) + } +} diff --git a/src/main/scala/chisel3/compatibility/throwException.scala b/src/main/scala/chisel3/compatibility/throwException.scala new file mode 100644 index 00000000..702884aa --- /dev/null +++ b/src/main/scala/chisel3/compatibility/throwException.scala @@ -0,0 +1,12 @@ +// See LICENSE for license details. + +package Chisel + +@deprecated("throwException doesn't exist in Chisel3", "3.0.0") +@throws(classOf[Exception]) +object throwException { + def apply(s: String, t: Throwable = null) = { + val xcpt = new Exception(s, t) + throw xcpt + } +} diff --git a/src/main/scala/chisel3/internal/firrtl/Emitter.scala b/src/main/scala/chisel3/internal/firrtl/Emitter.scala new file mode 100644 index 00000000..7ca3268a --- /dev/null +++ b/src/main/scala/chisel3/internal/firrtl/Emitter.scala @@ -0,0 +1,112 @@ +// See LICENSE for license details. + +package Chisel.internal.firrtl +import Chisel._ +import Chisel.internal.sourceinfo.{NoSourceInfo, SourceLine} + +private[Chisel] object Emitter { + def emit(circuit: Circuit): String = new Emitter(circuit).toString +} + +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 = { + val firrtlLine = 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() + s"skip" + } + e.sourceInfo match { + case SourceLine(filename, line, col) => s"${firrtlLine} @[${filename} ${line}:${col}] " + case _: NoSourceInfo => firrtlLine + } + } + + // 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/src/main/scala/chisel3/package.scala b/src/main/scala/chisel3/package.scala new file mode 100644 index 00000000..f05e8b5d --- /dev/null +++ b/src/main/scala/chisel3/package.scala @@ -0,0 +1,31 @@ +package object Chisel { + import scala.language.experimental.macros + + import internal.firrtl.Width + import internal.sourceinfo.{SourceInfo, SourceInfoTransform} + + implicit class fromBigIntToLiteral(val x: BigInt) extends AnyVal { + def U: UInt = UInt(x, Width()) + def S: SInt = SInt(x, Width()) + } + implicit class fromIntToLiteral(val x: Int) extends AnyVal { + def U: UInt = UInt(BigInt(x), Width()) + def S: SInt = SInt(BigInt(x), Width()) + } + implicit class fromStringToLiteral(val x: String) extends AnyVal { + def U: UInt = UInt(x) + } + implicit class fromBooleanToLiteral(val x: Boolean) extends AnyVal { + def B: Bool = Bool(x) + } + + implicit class fromUIntToBitPatComparable(val x: UInt) extends AnyVal { + final def === (that: BitPat): Bool = macro SourceInfoTransform.thatArg + final def != (that: BitPat): Bool = macro SourceInfoTransform.thatArg + final def =/= (that: BitPat): Bool = macro SourceInfoTransform.thatArg + + def do_=== (that: BitPat)(implicit sourceInfo: SourceInfo): Bool = that === x + def do_!= (that: BitPat)(implicit sourceInfo: SourceInfo): Bool = that != x + def do_=/= (that: BitPat)(implicit sourceInfo: SourceInfo): Bool = that =/= x + } +} diff --git a/src/main/scala/chisel3/testers/BasicTester.scala b/src/main/scala/chisel3/testers/BasicTester.scala new file mode 100644 index 00000000..b8c1494a --- /dev/null +++ b/src/main/scala/chisel3/testers/BasicTester.scala @@ -0,0 +1,38 @@ +// See LICENSE for license details. + +package Chisel.testers +import Chisel._ + +import scala.language.experimental.macros + +import internal._ +import internal.Builder.pushCommand +import internal.firrtl._ +import internal.sourceinfo.SourceInfo + +class BasicTester extends Module { + // The testbench has no IOs, rather it should communicate using printf, assert, and stop. + val io = new Bundle() + + def popCount(n: Long): Int = n.toBinaryString.count(_=='1') + + /** Ends the test reporting success. + * + * 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. + */ + def stop()(implicit sourceInfo: SourceInfo) { + // TODO: rewrite this using library-style SourceInfo passing. + when (!reset) { + pushCommand(Stop(sourceInfo, Node(clock), 0)) + } + } + + /** The finish method provides a hook that subclasses of BasicTester can use to + * alter a circuit after their constructor has been called. + * For example, a specialized tester subclassing BasicTester could override finish in order to + * add flow control logic for a decoupled io port of a device under test + */ + def finish(): Unit = {} +} diff --git a/src/main/scala/chisel3/testers/TesterDriver.scala b/src/main/scala/chisel3/testers/TesterDriver.scala new file mode 100644 index 00000000..a56bb8b7 --- /dev/null +++ b/src/main/scala/chisel3/testers/TesterDriver.scala @@ -0,0 +1,68 @@ +// See LICENSE for license details. + +package Chisel.testers +import Chisel._ +import scala.io.Source +import scala.sys.process._ +import java.io._ + +object TesterDriver extends BackendCompilationUtilities { + /** Copy the contents of a resource to a destination file. + */ + def copyResourceToFile(name: String, file: File) { + val in = getClass().getResourceAsStream(name) + if (in == null) { + throw new FileNotFoundException(s"Resource '$name'") + } + val out = new FileOutputStream(file) + Iterator.continually(in.read).takeWhile(-1 !=).foreach(out.write) + out.close() + } + + /** For use with modules that should successfully be elaborated by the + * frontend, and which can be turned into executables with assertions. */ + def execute(t: () => BasicTester, additionalVResources: Seq[String] = Seq()): Boolean = { + // Invoke the chisel compiler to get the circuit's IR + val circuit = Driver.elaborate(finishWrapper(t)) + + // Set up a bunch of file handlers based on a random temp filename, + // plus the quirks of Verilator's naming conventions + val target = circuit.name + + val path = createTempDirectory(target) + val fname = new File(path, target) + + // For now, dump the IR out to a file + Driver.dumpFirrtl(circuit, Some(new File(fname.toString + ".fir"))) + + // Copy CPP harness and other Verilog sources from resources into files + val cppHarness = new File(path, "top.cpp") + copyResourceToFile("/top.cpp", cppHarness) + val additionalVFiles = additionalVResources.map((name: String) => { + val mangledResourceName = name.replace("/", "_") + val out = new File(path, mangledResourceName) + copyResourceToFile(name, out) + out + }) + + // Use sys.Process to invoke a bunch of backend stuff, then run the resulting exe + if ((firrtlToVerilog(target, path) #&& + verilogToCpp(target, target, path, additionalVFiles, cppHarness) #&& + cppToExe(target, path)).! == 0) { + executeExpectingSuccess(target, path) + } else { + false + } + } + /** + * Calls the finish method of an BasicTester or a class that extends it. + * The finish method is a hook for code that augments the circuit built in the constructor. + */ + def finishWrapper(test: () => BasicTester): () => BasicTester = { + () => { + val tester = test() + tester.finish() + tester + } + } +} diff --git a/src/main/scala/chisel3/util/Arbiter.scala b/src/main/scala/chisel3/util/Arbiter.scala new file mode 100644 index 00000000..16ae9be5 --- /dev/null +++ b/src/main/scala/chisel3/util/Arbiter.scala @@ -0,0 +1,117 @@ +// See LICENSE for license details. + +/** Arbiters in all shapes and sizes. + */ + +package Chisel + +/** An I/O bundle for the Arbiter */ +class ArbiterIO[T <: Data](gen: T, n: Int) extends Bundle { + val in = Vec(n, Decoupled(gen)).flip + val out = Decoupled(gen) + val chosen = UInt(OUTPUT, log2Up(n)) +} + +/** Arbiter Control determining which producer has access */ +private object ArbiterCtrl +{ + def apply(request: Seq[Bool]): Seq[Bool] = request.length match { + case 0 => Seq() + case 1 => Seq(Bool(true)) + case _ => Bool(true) +: request.tail.init.scanLeft(request.head)(_ || _).map(!_) + } +} + +abstract class LockingArbiterLike[T <: Data](gen: T, n: Int, count: Int, needsLock: Option[T => Bool]) extends Module { + def grant: Seq[Bool] + def choice: UInt + val io = new ArbiterIO(gen, n) + + io.chosen := choice + io.out.valid := io.in(io.chosen).valid + io.out.bits := io.in(io.chosen).bits + + if (count > 1) { + val lockCount = Counter(count) + val lockIdx = Reg(UInt()) + val locked = lockCount.value =/= UInt(0) + val wantsLock = needsLock.map(_(io.out.bits)).getOrElse(Bool(true)) + + when (io.out.fire() && wantsLock) { + lockIdx := io.chosen + lockCount.inc() + } + + when (locked) { io.chosen := lockIdx } + for ((in, (g, i)) <- io.in zip grant.zipWithIndex) + in.ready := Mux(locked, lockIdx === UInt(i), g) && io.out.ready + } else { + for ((in, g) <- io.in zip grant) + in.ready := g && io.out.ready + } +} + +class LockingRRArbiter[T <: Data](gen: T, n: Int, count: Int, needsLock: Option[T => Bool] = None) + extends LockingArbiterLike[T](gen, n, count, needsLock) { + lazy val lastGrant = RegEnable(io.chosen, io.out.fire()) + lazy val grantMask = (0 until n).map(UInt(_) > lastGrant) + lazy val validMask = io.in zip grantMask map { case (in, g) => in.valid && g } + + override def grant: Seq[Bool] = { + val ctrl = ArbiterCtrl((0 until n).map(i => validMask(i)) ++ io.in.map(_.valid)) + (0 until n).map(i => ctrl(i) && grantMask(i) || ctrl(i + n)) + } + + override lazy val choice = Wire(init=UInt(n-1)) + for (i <- n-2 to 0 by -1) + when (io.in(i).valid) { choice := UInt(i) } + for (i <- n-1 to 1 by -1) + when (validMask(i)) { choice := UInt(i) } +} + +class LockingArbiter[T <: Data](gen: T, n: Int, count: Int, needsLock: Option[T => Bool] = None) + extends LockingArbiterLike[T](gen, n, count, needsLock) { + def grant: Seq[Bool] = ArbiterCtrl(io.in.map(_.valid)) + + override lazy val choice = Wire(init=UInt(n-1)) + for (i <- n-2 to 0 by -1) + when (io.in(i).valid) { choice := UInt(i) } +} + +/** Hardware module that is used to sequence n producers into 1 consumer. + Producers are chosen in round robin order. + + Example usage: + val arb = new RRArbiter(2, UInt()) + arb.io.in(0) <> producer0.io.out + arb.io.in(1) <> producer1.io.out + consumer.io.in <> arb.io.out + */ +class RRArbiter[T <: Data](gen:T, n: Int) extends LockingRRArbiter[T](gen, n, 1) + +/** Hardware module that is used to sequence n producers into 1 consumer. + Priority is given to lower producer + + Example usage: + val arb = Module(new Arbiter(2, UInt())) + arb.io.in(0) <> producer0.io.out + arb.io.in(1) <> producer1.io.out + consumer.io.in <> arb.io.out + */ +class Arbiter[T <: Data](gen: T, n: Int) extends Module { + val io = new ArbiterIO(gen, n) + + io.chosen := UInt(n-1) + io.out.bits := io.in(n-1).bits + for (i <- n-2 to 0 by -1) { + when (io.in(i).valid) { + io.chosen := UInt(i) + io.out.bits := io.in(i).bits + } + } + + val grant = ArbiterCtrl(io.in.map(_.valid)) + for ((in, g) <- io.in zip grant) + in.ready := g && io.out.ready + io.out.valid := !grant.last || io.in.last.valid +} diff --git a/src/main/scala/chisel3/util/BitPat.scala b/src/main/scala/chisel3/util/BitPat.scala new file mode 100644 index 00000000..96206f63 --- /dev/null +++ b/src/main/scala/chisel3/util/BitPat.scala @@ -0,0 +1,88 @@ +// See LICENSE for license details. + +package Chisel + +import scala.language.experimental.macros + +import Chisel.internal.sourceinfo.{SourceInfo, SourceInfoTransform} + +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) + */ + 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 + */ + 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 === (that: UInt): Bool = macro SourceInfoTransform.thatArg + def =/= (that: UInt): Bool = macro SourceInfoTransform.thatArg + def != (that: UInt): Bool = macro SourceInfoTransform.thatArg + + def do_=== (that: UInt)(implicit sourceInfo: SourceInfo): Bool = UInt(value) === (that & UInt(mask)) + def do_=/= (that: UInt)(implicit sourceInfo: SourceInfo): Bool = !(this === that) + def do_!= (that: UInt)(implicit sourceInfo: SourceInfo): Bool = this =/= that +} diff --git a/src/main/scala/chisel3/util/Bitwise.scala b/src/main/scala/chisel3/util/Bitwise.scala new file mode 100644 index 00000000..239a295e --- /dev/null +++ b/src/main/scala/chisel3/util/Bitwise.scala @@ -0,0 +1,71 @@ +// See LICENSE for license details. + +/** Miscellaneous circuit generators operating on bits. + */ + +package Chisel + +object FillInterleaved +{ + def apply(n: Int, in: UInt): UInt = apply(n, in.toBools) + def apply(n: Int, in: Seq[Bool]): UInt = Vec(in.map(Fill(n, _))).toBits +} + +/** Returns the number of bits set (i.e value is 1) in the input signal. + */ +object PopCount +{ + def apply(in: Iterable[Bool]): UInt = SeqUtils.count(in.toSeq) + def apply(in: Bits): UInt = apply((0 until in.getWidth).map(in(_))) +} + +/** Fill fans out a UInt to multiple copies */ +object Fill { + /** Fan out x n times */ + def apply(n: Int, x: UInt): UInt = { + n match { + case 0 => UInt(width=0) + case 1 => x + case y if n > 1 => + val p2 = Array.ofDim[UInt](log2Up(n + 1)) + p2(0) = x + for (i <- 1 until p2.length) + p2(i) = Cat(p2(i-1), p2(i-1)) + Cat((0 until log2Up(y + 1)).filter(i => (y & (1 << i)) != 0).map(p2(_))) + case _ => throw new IllegalArgumentException(s"n (=$n) must be nonnegative integer.") + } + } + /** Fan out x n times */ + def apply(n: Int, x: Bool): UInt = + if (n > 1) { + UInt(0,n) - x + } else { + apply(n, x: UInt) + } +} + +/** Litte/big bit endian convertion: reverse the order of the bits in a UInt. +*/ +object Reverse +{ + private def doit(in: UInt, length: Int): UInt = { + if (length == 1) { + in + } else if (isPow2(length) && length >= 8 && length <= 64) { + // This esoterica improves simulation performance + var res = in + var shift = length >> 1 + var mask = UInt((BigInt(1) << length) - 1, length) + do { + mask = mask ^ (mask(length-shift-1,0) << shift) + res = ((res >> shift) & mask) | ((res(length-shift-1,0) << shift) & ~mask) + shift = shift >> 1 + } while (shift > 0) + res + } else { + val half = (1 << log2Up(length))/2 + Cat(doit(in(half-1,0), half), doit(in(length-1,half), length-half)) + } + } + def apply(in: UInt): UInt = doit(in, in.getWidth) +} diff --git a/src/main/scala/chisel3/util/Cat.scala b/src/main/scala/chisel3/util/Cat.scala new file mode 100644 index 00000000..dd706e62 --- /dev/null +++ b/src/main/scala/chisel3/util/Cat.scala @@ -0,0 +1,18 @@ +// See LICENSE for license details. + +package Chisel + +object Cat { + /** Combine data elements together + * @param a Data to combine with + * @param r any number of other Data elements to be combined in order + * @return A UInt which is all of the bits combined together + */ + def apply[T <: Bits](a: T, r: T*): UInt = apply(a :: r.toList) + + /** Combine data elements together + * @param r any number of other Data elements to be combined in order + * @return A UInt which is all of the bits combined together + */ + def apply[T <: Bits](r: Seq[T]): UInt = SeqUtils.asUInt(r.reverse) +} diff --git a/src/main/scala/chisel3/util/CircuitMath.scala b/src/main/scala/chisel3/util/CircuitMath.scala new file mode 100644 index 00000000..06cab903 --- /dev/null +++ b/src/main/scala/chisel3/util/CircuitMath.scala @@ -0,0 +1,26 @@ +// See LICENSE for license details. + +/** Circuit-land math operations. + */ + +package Chisel + +/** Compute Log2 with truncation of a UInt in hardware using a Mux Tree + * An alternative interpretation is it computes the minimum number of bits needed to represent x + * @example + * {{{ data_out := Log2(data_in) }}} + * @note Truncation is used so Log2(UInt(12412)) = 13*/ +object Log2 { + /** Compute the Log2 on the least significant n bits of x */ + def apply(x: Bits, width: Int): UInt = { + if (width < 2) { + UInt(0) + } else if (width == 2) { + x(1) + } else { + Mux(x(width-1), UInt(width-1), apply(x, width-1)) + } + } + + def apply(x: Bits): UInt = apply(x, x.getWidth) +} diff --git a/src/main/scala/chisel3/util/Conditional.scala b/src/main/scala/chisel3/util/Conditional.scala new file mode 100644 index 00000000..9cab25ef --- /dev/null +++ b/src/main/scala/chisel3/util/Conditional.scala @@ -0,0 +1,69 @@ +// See LICENSE for license details. + +/** Conditional blocks. + */ + +package Chisel + +import scala.language.reflectiveCalls +import scala.language.experimental.macros +import scala.reflect.runtime.universe._ +import scala.reflect.macros.blackbox._ + +/** This is identical to [[Chisel.when when]] with the condition inverted */ +object unless { // scalastyle:ignore object.name + def apply(c: Bool)(block: => Unit) { + when (!c) { block } + } +} + +class SwitchContext[T <: Bits](cond: T) { + def is(v: Iterable[T])(block: => Unit) { + if (!v.isEmpty) when (v.map(_.asUInt === cond.asUInt).reduce(_||_)) { block } + } + def is(v: T)(block: => Unit) { is(Seq(v))(block) } + def is(v: T, vr: T*)(block: => Unit) { is(v :: vr.toList)(block) } +} + +/** An object for separate cases in [[Chisel.switch switch]] + * It is equivalent to a [[Chisel.when$ when]] block comparing to the condition + * Use outside of a switch statement is illegal */ +object is { // scalastyle:ignore object.name + // Begin deprecation of non-type-parameterized is statements. + def apply(v: Iterable[Bits])(block: => Unit) { + require(false, "The 'is' keyword may not be used outside of a switch.") + } + + def apply(v: Bits)(block: => Unit) { + require(false, "The 'is' keyword may not be used outside of a switch.") + } + + def apply(v: Bits, vr: Bits*)(block: => Unit) { + require(false, "The 'is' keyword may not be used outside of a switch.") + } +} + +/** Conditional logic to form a switch block + * @example + * {{{ ... // default values here + * switch ( myState ) { + * is( state1 ) { + * ... // some logic here + * } + * is( state2 ) { + * ... // some logic here + * } + * } }}}*/ +object switch { // scalastyle:ignore object.name + def apply[T <: Bits](cond: T)(x: => Unit): Unit = macro impl + def impl(c: Context)(cond: c.Tree)(x: c.Tree): c.Tree = { import c.universe._ + val sc = c.universe.internal.reificationSupport.freshTermName("sc") + def extractIsStatement(tree: Tree): List[c.universe.Tree] = tree match { + case q"Chisel.is.apply( ..$params )( ..$body )" => List(q"$sc.is( ..$params )( ..$body )") + case b => throw new Exception(s"Cannot include blocks that do not begin with is() in switch.") + } + val q"..$body" = x + val ises = body.flatMap(extractIsStatement(_)) + q"""{ val $sc = new SwitchContext($cond); ..$ises }""" + } +} diff --git a/src/main/scala/chisel3/util/Counter.scala b/src/main/scala/chisel3/util/Counter.scala new file mode 100644 index 00000000..872e830a --- /dev/null +++ b/src/main/scala/chisel3/util/Counter.scala @@ -0,0 +1,44 @@ +// See LICENSE for license details. + +package Chisel + +/** A counter module + * @param n number of counts before the counter resets (or one more than the + * maximum output value of the counter), need not be a power of two + */ +class Counter(val n: Int) { + require(n >= 0) + val value = if (n > 1) Reg(init=UInt(0, log2Up(n))) else UInt(0) + /** Increment the counter, returning whether the counter currently is at the + * maximum and will wrap. The incremented value is registered and will be + * visible on the next cycle. + */ + def inc(): Bool = { + if (n > 1) { + val wrap = value === UInt(n-1) + value := value + UInt(1) + if (!isPow2(n)) { + when (wrap) { value := UInt(0) } + } + wrap + } else { + Bool(true) + } + } +} + +/** Counter Object + * Example Usage: + * {{{ val countOn = Bool(true) // increment counter every clock cycle + * val myCounter = Counter(countOn, n) + * when ( myCounter.value === UInt(3) ) { ... } }}}*/ +object Counter +{ + def apply(n: Int): Counter = new Counter(n) + def apply(cond: Bool, n: Int): (UInt, Bool) = { + val c = new Counter(n) + var wrap: Bool = null + when (cond) { wrap = c.inc() } + (c.value, cond && wrap) + } +} diff --git a/src/main/scala/chisel3/util/Decoupled.scala b/src/main/scala/chisel3/util/Decoupled.scala new file mode 100644 index 00000000..8e045855 --- /dev/null +++ b/src/main/scala/chisel3/util/Decoupled.scala @@ -0,0 +1,183 @@ +// See LICENSE for license details. + +/** Wrappers for ready-valid (Decoupled) interfaces and associated circuit generators using them. + */ + +package Chisel + +/** An I/O Bundle with simple handshaking using valid and ready signals for data 'bits'*/ +class DecoupledIO[+T <: Data](gen: T) extends Bundle +{ + val ready = Bool(INPUT) + val valid = Bool(OUTPUT) + val bits = gen.cloneType.asOutput + def fire(dummy: Int = 0): Bool = ready && valid + override def cloneType: this.type = new DecoupledIO(gen).asInstanceOf[this.type] +} + +/** Adds a ready-valid handshaking protocol to any interface. + * The standard used is that the consumer uses the flipped interface. + */ +object Decoupled { + def apply[T <: Data](gen: T): DecoupledIO[T] = new DecoupledIO(gen) +} + +/** An I/O bundle for enqueuing data with valid/ready handshaking + * Initialization must be handled, if necessary, by the parent circuit + */ +class EnqIO[T <: Data](gen: T) extends DecoupledIO(gen) +{ + /** push dat onto the output bits of this interface to let the consumer know it has happened. + * @param dat the values to assign to bits. + * @return dat. + */ + def enq(dat: T): T = { valid := Bool(true); bits := dat; dat } + + /** Initialize this Bundle. Valid is set to false, and all bits are set to zero. + * NOTE: This method of initialization is still being discussed and could change in the + * future. + */ + def init(): Unit = { + valid := Bool(false) + for (io <- bits.flatten) + io := UInt(0) + } + override def cloneType: this.type = { new EnqIO(gen).asInstanceOf[this.type]; } +} + +/** An I/O bundle for dequeuing data with valid/ready handshaking. + * Initialization must be handled, if necessary, by the parent circuit + */ +class DeqIO[T <: Data](gen: T) extends DecoupledIO(gen) with Flipped +{ + /** Assert ready on this port and return the associated data bits. + * This is typically used when valid has been asserted by the producer side. + * @param b ignored + * @return the data for this device, + */ + def deq(b: Boolean = false): T = { ready := Bool(true); bits } + + /** Initialize this Bundle. + * NOTE: This method of initialization is still being discussed and could change in the + * future. + */ + def init(): Unit = { + ready := Bool(false) + } + override def cloneType: this.type = { new DeqIO(gen).asInstanceOf[this.type]; } +} + +/** An I/O bundle for dequeuing data with valid/ready handshaking */ +class DecoupledIOC[+T <: Data](gen: T) extends Bundle +{ + val ready = Bool(INPUT) + val valid = Bool(OUTPUT) + val bits = gen.cloneType.asOutput +} + +/** An I/O Bundle for Queues + * @param gen The type of data to queue + * @param entries The max number of entries in the queue */ +class QueueIO[T <: Data](gen: T, entries: Int) extends Bundle +{ + /** I/O to enqueue data, is [[Chisel.DecoupledIO]] flipped */ + val enq = Decoupled(gen.cloneType).flip() + /** I/O to enqueue data, is [[Chisel.DecoupledIO]]*/ + val deq = Decoupled(gen.cloneType) + /** The current amount of data in the queue */ + val count = UInt(OUTPUT, log2Up(entries + 1)) +} + +/** A hardware module implementing a Queue + * @param gen The type of data to queue + * @param entries The max number of entries in the queue + * @param pipe True if a single entry queue can run at full throughput (like a pipeline). The ''ready'' signals are + * combinationally coupled. + * @param flow True if the inputs can be consumed on the same cycle (the inputs "flow" through the queue immediately). + * The ''valid'' signals are coupled. + * + * Example usage: + * {{{ val q = new Queue(UInt(), 16) + * q.io.enq <> producer.io.out + * consumer.io.in <> q.io.deq }}} + */ +class Queue[T <: Data](gen: T, val entries: Int, + pipe: Boolean = false, + flow: Boolean = false, + override_reset: Option[Bool] = None) +extends Module(override_reset=override_reset) { + def this(gen: T, entries: Int, pipe: Boolean, flow: Boolean, _reset: Bool) = + this(gen, entries, pipe, flow, Some(_reset)) + + val io = new QueueIO(gen, entries) + + val ram = Mem(entries, gen) + val enq_ptr = Counter(entries) + val deq_ptr = Counter(entries) + val maybe_full = Reg(init=Bool(false)) + + val ptr_match = enq_ptr.value === deq_ptr.value + val empty = ptr_match && !maybe_full + val full = ptr_match && maybe_full + val do_enq = Wire(init=io.enq.fire()) + val do_deq = Wire(init=io.deq.fire()) + + when (do_enq) { + ram(enq_ptr.value) := io.enq.bits + enq_ptr.inc() + } + when (do_deq) { + deq_ptr.inc() + } + when (do_enq != do_deq) { + maybe_full := do_enq + } + + io.deq.valid := !empty + io.enq.ready := !full + io.deq.bits := ram(deq_ptr.value) + + if (flow) { + when (io.enq.valid) { io.deq.valid := Bool(true) } + when (empty) { + io.deq.bits := io.enq.bits + do_deq := Bool(false) + when (io.deq.ready) { do_enq := Bool(false) } + } + } + + if (pipe) { + when (io.deq.ready) { io.enq.ready := Bool(true) } + } + + val ptr_diff = enq_ptr.value - deq_ptr.value + if (isPow2(entries)) { + io.count := Cat(maybe_full && ptr_match, ptr_diff) + } else { + io.count := Mux(ptr_match, + Mux(maybe_full, + UInt(entries), UInt(0)), + Mux(deq_ptr.value > enq_ptr.value, + UInt(entries) + ptr_diff, ptr_diff)) + } +} + +/** Generic hardware queue. Required parameter entries controls + the depth of the queues. The width of the queue is determined + from the inputs. + + Example usage: + {{{ val q = Queue(Decoupled(UInt()), 16) + q.io.enq <> producer.io.out + consumer.io.in <> q.io.deq }}} + */ +object Queue +{ + def apply[T <: Data](enq: DecoupledIO[T], entries: Int = 2, pipe: Boolean = false): DecoupledIO[T] = { + val q = Module(new Queue(enq.bits.cloneType, entries, pipe)) + q.io.enq.valid := enq.valid // not using <> so that override is allowed + q.io.enq.bits := enq.bits + enq.ready := q.io.enq.ready + TransitName(q.io.deq, q) + } +} diff --git a/src/main/scala/chisel3/util/Enum.scala b/src/main/scala/chisel3/util/Enum.scala new file mode 100644 index 00000000..20057197 --- /dev/null +++ b/src/main/scala/chisel3/util/Enum.scala @@ -0,0 +1,21 @@ +// See LICENSE for license details. + +/** Enum generators, allowing circuit constants to have more meaningful names. + */ + +package Chisel + +object Enum { + /** Returns a sequence of Bits subtypes with values from 0 until n. Helper method. */ + private def createValues[T <: Bits](nodeType: T, n: Int): Seq[T] = + (0 until n).map(x => nodeType.fromInt(x, log2Up(n))) + + /** create n enum values of given type */ + def apply[T <: Bits](nodeType: T, n: Int): List[T] = createValues(nodeType, n).toList + + /** create enum values of given type and names */ + def apply[T <: Bits](nodeType: T, l: Symbol *): Map[Symbol, T] = (l zip createValues(nodeType, l.length)).toMap + + /** create enum values of given type and names */ + def apply[T <: Bits](nodeType: T, l: List[Symbol]): Map[Symbol, T] = (l zip createValues(nodeType, l.length)).toMap +} diff --git a/src/main/scala/chisel3/util/ImplicitConversions.scala b/src/main/scala/chisel3/util/ImplicitConversions.scala new file mode 100644 index 00000000..6a230022 --- /dev/null +++ b/src/main/scala/chisel3/util/ImplicitConversions.scala @@ -0,0 +1,8 @@ +// See LICENSE for license details. + +package Chisel + +object ImplicitConversions { + implicit def intToUInt(x: Int): UInt = UInt(x) + implicit def booleanToBool(x: Boolean): Bool = Bool(x) +} diff --git a/src/main/scala/chisel3/util/LFSR.scala b/src/main/scala/chisel3/util/LFSR.scala new file mode 100644 index 00000000..839b1d1f --- /dev/null +++ b/src/main/scala/chisel3/util/LFSR.scala @@ -0,0 +1,22 @@ +// See LICENSE for license details. + +/** LFSRs in all shapes and sizes. + */ + +package Chisel + +// scalastyle:off magic.number +/** linear feedback shift register + */ +object LFSR16 +{ + def apply(increment: Bool = Bool(true)): UInt = + { + val width = 16 + val lfsr = Reg(init=UInt(1, width)) + when (increment) { lfsr := Cat(lfsr(0)^lfsr(2)^lfsr(3)^lfsr(5), lfsr(width-1,1)) } + lfsr + } +} +// scalastyle:on magic.number + diff --git a/src/main/scala/chisel3/util/Lookup.scala b/src/main/scala/chisel3/util/Lookup.scala new file mode 100644 index 00000000..54922fc4 --- /dev/null +++ b/src/main/scala/chisel3/util/Lookup.scala @@ -0,0 +1,17 @@ +// See LICENSE for license details. + +package Chisel + +object ListLookup { + def apply[T <: Data](addr: UInt, default: List[T], mapping: Array[(BitPat, List[T])]): List[T] = { + val map = mapping.map(m => (m._1 === addr, m._2)) + default.zipWithIndex map { case (d, i) => + map.foldRight(d)((m, n) => Mux(m._1, m._2(i), n)) + } + } +} + +object Lookup { + def apply[T <: Bits](addr: UInt, default: T, mapping: Seq[(BitPat, T)]): T = + ListLookup(addr, List(default), mapping.map(m => (m._1, List(m._2))).toArray).head +} diff --git a/src/main/scala/chisel3/util/Math.scala b/src/main/scala/chisel3/util/Math.scala new file mode 100644 index 00000000..5f8212d8 --- /dev/null +++ b/src/main/scala/chisel3/util/Math.scala @@ -0,0 +1,42 @@ +// See LICENSE for license details. + +/** Scala-land math helper functions, like logs. + */ + +package Chisel + +/** Compute the log2 rounded up with min value of 1 */ +object log2Up { + def apply(in: BigInt): Int = { + require(in >= 0) + 1 max (in-1).bitLength + } + def apply(in: Int): Int = apply(BigInt(in)) +} + +/** Compute the log2 rounded up */ +object log2Ceil { + def apply(in: BigInt): Int = { + require(in > 0) + (in-1).bitLength + } + def apply(in: Int): Int = apply(BigInt(in)) +} + +/** Compute the log2 rounded down with min value of 1 */ +object log2Down { + def apply(in: BigInt): Int = log2Up(in) - (if (isPow2(in)) 0 else 1) + def apply(in: Int): Int = apply(BigInt(in)) +} + +/** Compute the log2 rounded down */ +object log2Floor { + def apply(in: BigInt): Int = log2Ceil(in) - (if (isPow2(in)) 0 else 1) + def apply(in: Int): Int = apply(BigInt(in)) +} + +/** Check if an Integer is a power of 2 */ +object isPow2 { + def apply(in: BigInt): Boolean = in > 0 && ((in & (in-1)) == 0) + def apply(in: Int): Boolean = apply(BigInt(in)) +} diff --git a/src/main/scala/chisel3/util/Mux.scala b/src/main/scala/chisel3/util/Mux.scala new file mode 100644 index 00000000..9d92321a --- /dev/null +++ b/src/main/scala/chisel3/util/Mux.scala @@ -0,0 +1,61 @@ +// See LICENSE for license details. + +/** Mux circuit generators. + */ + +package Chisel + +/** Builds a Mux tree out of the input signal vector using a one hot encoded + select signal. Returns the output of the Mux tree. + */ +object Mux1H +{ + def apply[T <: Data](sel: Seq[Bool], in: Seq[T]): T = + apply(sel zip in) + def apply[T <: Data](in: Iterable[(Bool, T)]): T = SeqUtils.oneHotMux(in) + def apply[T <: Data](sel: UInt, in: Seq[T]): T = + apply((0 until in.size).map(sel(_)), in) + def apply(sel: UInt, in: UInt): Bool = (sel & in).orR +} + +/** Builds a Mux tree under the assumption that multiple select signals + can be enabled. Priority is given to the first select signal. + + Returns the output of the Mux tree. + */ +object PriorityMux +{ + def apply[T <: Data](in: Seq[(Bool, T)]): T = SeqUtils.priorityMux(in) + def apply[T <: Data](sel: Seq[Bool], in: Seq[T]): T = apply(sel zip in) + def apply[T <: Data](sel: Bits, in: Seq[T]): T = apply((0 until in.size).map(sel(_)), in) +} + +/** MuxLookup creates a cascade of n Muxs to search for a key value */ +object MuxLookup { + /** @param key a key to search for + * @param default a default value if nothing is found + * @param mapping a sequence to search of keys and values + * @return the value found or the default if not + */ + def apply[S <: UInt, T <: Bits] (key: S, default: T, mapping: Seq[(S, T)]): T = { + var res = default + for ((k, v) <- mapping.reverse) + res = Mux(k === key, v, res) + res + } + +} + +/** MuxCase returns the first value that is enabled in a map of values */ +object MuxCase { + /** @param default the default value if none are enabled + * @param mapping a set of data values with associated enables + * @return the first value in mapping that is enabled */ + def apply[T <: Bits] (default: T, mapping: Seq[(Bool, T)]): T = { + var res = default + for ((t, v) <- mapping.reverse){ + res = Mux(t, v, res) + } + res + } +} diff --git a/src/main/scala/chisel3/util/OneHot.scala b/src/main/scala/chisel3/util/OneHot.scala new file mode 100644 index 00000000..73f27403 --- /dev/null +++ b/src/main/scala/chisel3/util/OneHot.scala @@ -0,0 +1,62 @@ +// See LICENSE for license details. + +/** Circuit generators for working with one-hot representations. + */ + +package Chisel + +/** Converts from One Hot Encoding to a UInt indicating which bit is active + * This is the inverse of [[Chisel.UIntToOH UIntToOH]]*/ +object OHToUInt { + def apply(in: Seq[Bool]): UInt = apply(Vec(in)) + def apply(in: Vec[Bool]): UInt = apply(in.toBits, in.size) + def apply(in: Bits): UInt = apply(in, in.getWidth) + + def apply(in: Bits, width: Int): UInt = { + if (width <= 2) { + Log2(in, width) + } else { + val mid = 1 << (log2Up(width)-1) + val hi = in(width-1, mid) + val lo = in(mid-1, 0) + Cat(hi.orR, apply(hi | lo, mid)) + } + } +} + +/** @return the bit position of the trailing 1 in the input vector + * with the assumption that multiple bits of the input bit vector can be set + * @example {{{ data_out := PriorityEncoder(data_in) }}} + */ +object PriorityEncoder { + def apply(in: Seq[Bool]): UInt = PriorityMux(in, (0 until in.size).map(UInt(_))) + def apply(in: Bits): UInt = apply(in.toBools) +} + +/** Returns the one hot encoding of the input UInt. + */ +object UIntToOH +{ + def apply(in: UInt, width: Int = -1): UInt = + if (width == -1) { + UInt(1) << in + } else { + (UInt(1) << in(log2Up(width)-1,0))(width-1,0) + } +} + +/** Returns a bit vector in which only the least-significant 1 bit in + the input vector, if any, is set. + */ +object PriorityEncoderOH +{ + private def encode(in: Seq[Bool]): UInt = { + val outs = Seq.tabulate(in.size)(i => UInt(BigInt(1) << i, in.size)) + PriorityMux(in :+ Bool(true), outs :+ UInt(0, in.size)) + } + def apply(in: Seq[Bool]): Seq[Bool] = { + val enc = encode(in) + Seq.tabulate(in.size)(enc(_)) + } + def apply(in: Bits): UInt = encode((0 until in.getWidth).map(i => in(i))) +} diff --git a/src/main/scala/chisel3/util/Reg.scala b/src/main/scala/chisel3/util/Reg.scala new file mode 100644 index 00000000..6584a4bf --- /dev/null +++ b/src/main/scala/chisel3/util/Reg.scala @@ -0,0 +1,55 @@ +// See LICENSE for license details. + +/** Variations and helpers for registers. + */ + +package Chisel + +object RegNext { + + def apply[T <: Data](next: T): T = Reg[T](null.asInstanceOf[T], next, null.asInstanceOf[T]) + + def apply[T <: Data](next: T, init: T): T = Reg[T](null.asInstanceOf[T], next, init) + +} + +object RegInit { + + def apply[T <: Data](init: T): T = Reg[T](null.asInstanceOf[T], null.asInstanceOf[T], init) + +} + +/** A register with an Enable signal */ +object RegEnable +{ + def apply[T <: Data](updateData: T, enable: Bool): T = { + val r = Reg(updateData) + when (enable) { r := updateData } + r + } + def apply[T <: Data](updateData: T, resetData: T, enable: Bool): T = { + val r = RegInit(resetData) + when (enable) { r := updateData } + r + } +} + +/** Returns the n-cycle delayed version of the input signal. + */ +object ShiftRegister +{ + /** @param in input to delay + * @param n number of cycles to delay + * @param en enable the shift */ + def apply[T <: Data](in: T, n: Int, en: Bool = Bool(true)): T = + { + // The order of tests reflects the expected use cases. + if (n == 1) { + RegEnable(in, en) + } else if (n != 0) { + RegNext(apply(in, n-1, en)) + } else { + in + } + } +} diff --git a/src/main/scala/chisel3/util/TransitName.scala b/src/main/scala/chisel3/util/TransitName.scala new file mode 100644 index 00000000..ec5a11cc --- /dev/null +++ b/src/main/scala/chisel3/util/TransitName.scala @@ -0,0 +1,21 @@ +package Chisel + +import internal.HasId + +object TransitName { + // The purpose of this is to allow a library to 'move' a name call to a more + // appropriate place. + // For example, a library factory function may create a module and return + // the io. The only user-exposed field is that given IO, which can't use + // any name supplied by the user. This can add a hook so that the supplied + // name then names the Module. + // See Queue companion object for working example + def apply[T<:HasId](from: T, to: HasId): T = { + from.addPostnameHook((given_name: String) => {to.suggestName(given_name)}) + from + } + def withSuffix[T<:HasId](suffix: String)(from: T, to: HasId): T = { + from.addPostnameHook((given_name: String) => {to.suggestName(given_name+suffix)}) + from + } +} diff --git a/src/main/scala/chisel3/util/Valid.scala b/src/main/scala/chisel3/util/Valid.scala new file mode 100644 index 00000000..9e2202bb --- /dev/null +++ b/src/main/scala/chisel3/util/Valid.scala @@ -0,0 +1,59 @@ +// See LICENSE for license details. + +/** Wrappers for valid interfaces and associated circuit generators using them. + */ + +package Chisel + +/** An I/O Bundle containing data and a signal determining if it is valid */ +class ValidIO[+T <: Data](gen2: T) extends Bundle +{ + val valid = Bool(OUTPUT) + val bits = gen2.cloneType.asOutput + def fire(dummy: Int = 0): Bool = valid + override def cloneType: this.type = new ValidIO(gen2).asInstanceOf[this.type] +} + +/** Adds a valid protocol to any interface. The standard used is + that the consumer uses the flipped interface. +*/ +object Valid { + def apply[T <: Data](gen: T): ValidIO[T] = new ValidIO(gen) +} + +/** A hardware module that delays data coming down the pipeline + by the number of cycles set by the latency parameter. Functionality + is similar to ShiftRegister but this exposes a Pipe interface. + + Example usage: + val pipe = new Pipe(UInt()) + pipe.io.enq <> produce.io.out + consumer.io.in <> pipe.io.deq + */ +object Pipe +{ + def apply[T <: Data](enqValid: Bool, enqBits: T, latency: Int): ValidIO[T] = { + if (latency == 0) { + val out = Wire(Valid(enqBits)) + out.valid <> enqValid + out.bits <> enqBits + out + } else { + val v = Reg(Bool(), next=enqValid, init=Bool(false)) + val b = RegEnable(enqBits, enqValid) + apply(v, b, latency-1) + } + } + def apply[T <: Data](enqValid: Bool, enqBits: T): ValidIO[T] = apply(enqValid, enqBits, 1) + def apply[T <: Data](enq: ValidIO[T], latency: Int = 1): ValidIO[T] = apply(enq.valid, enq.bits, latency) +} + +class Pipe[T <: Data](gen: T, latency: Int = 1) extends Module +{ + val io = new Bundle { + val enq = Valid(gen).flip + val deq = Valid(gen) + } + + io.deq <> Pipe(io.enq, latency) +} -- cgit v1.2.3