From 53813f61b7dfe246d214ab966739d01c65c8ecb0 Mon Sep 17 00:00:00 2001 From: Andrew Waterman Date: Wed, 8 Jun 2016 11:32:23 -0700 Subject: For Module instances we haven't named, suggest the Module class name --- chiselFrontend/src/main/scala/Chisel/Module.scala | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'chiselFrontend/src') diff --git a/chiselFrontend/src/main/scala/Chisel/Module.scala b/chiselFrontend/src/main/scala/Chisel/Module.scala index 20c9dd4a..e2101538 100644 --- a/chiselFrontend/src/main/scala/Chisel/Module.scala +++ b/chiselFrontend/src/main/scala/Chisel/Module.scala @@ -105,6 +105,12 @@ extends HasId { 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) -- cgit v1.2.3 From f36524e388b060b1bb535ae21cb1bcbbea220be9 Mon Sep 17 00:00:00 2001 From: ducky Date: Fri, 20 May 2016 18:09:57 -0700 Subject: Rename packages to lowercase chisel, add compatibility layer --- .../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/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 | 189 ++++++ 30 files changed, 2354 insertions(+), 2353 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/chisel/Aggregate.scala create mode 100644 chiselFrontend/src/main/scala/chisel/Assert.scala create mode 100644 chiselFrontend/src/main/scala/chisel/Bits.scala create mode 100644 chiselFrontend/src/main/scala/chisel/BlackBox.scala create mode 100644 chiselFrontend/src/main/scala/chisel/Data.scala create mode 100644 chiselFrontend/src/main/scala/chisel/Mem.scala create mode 100644 chiselFrontend/src/main/scala/chisel/Module.scala create mode 100644 chiselFrontend/src/main/scala/chisel/Printf.scala create mode 100644 chiselFrontend/src/main/scala/chisel/Reg.scala create mode 100644 chiselFrontend/src/main/scala/chisel/SeqUtils.scala create mode 100644 chiselFrontend/src/main/scala/chisel/When.scala create mode 100644 chiselFrontend/src/main/scala/chisel/internal/Builder.scala create mode 100644 chiselFrontend/src/main/scala/chisel/internal/Error.scala create mode 100644 chiselFrontend/src/main/scala/chisel/internal/SourceInfo.scala create mode 100644 chiselFrontend/src/main/scala/chisel/internal/firrtl/IR.scala (limited to 'chiselFrontend/src') 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/chisel/Aggregate.scala b/chiselFrontend/src/main/scala/chisel/Aggregate.scala new file mode 100644 index 00000000..4f3f3de0 --- /dev/null +++ b/chiselFrontend/src/main/scala/chisel/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/chisel/Assert.scala b/chiselFrontend/src/main/scala/chisel/Assert.scala new file mode 100644 index 00000000..0d660bc3 --- /dev/null +++ b/chiselFrontend/src/main/scala/chisel/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/chisel/Bits.scala b/chiselFrontend/src/main/scala/chisel/Bits.scala new file mode 100644 index 00000000..8ec7c1b9 --- /dev/null +++ b/chiselFrontend/src/main/scala/chisel/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/chisel/BlackBox.scala b/chiselFrontend/src/main/scala/chisel/BlackBox.scala new file mode 100644 index 00000000..1dabc18f --- /dev/null +++ b/chiselFrontend/src/main/scala/chisel/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/chisel/Data.scala b/chiselFrontend/src/main/scala/chisel/Data.scala new file mode 100644 index 00000000..c08adf9d --- /dev/null +++ b/chiselFrontend/src/main/scala/chisel/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/chisel/Mem.scala b/chiselFrontend/src/main/scala/chisel/Mem.scala new file mode 100644 index 00000000..5fd8b81e --- /dev/null +++ b/chiselFrontend/src/main/scala/chisel/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/chisel/Module.scala b/chiselFrontend/src/main/scala/chisel/Module.scala new file mode 100644 index 00000000..f7f8c0b5 --- /dev/null +++ b/chiselFrontend/src/main/scala/chisel/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/chisel/Printf.scala b/chiselFrontend/src/main/scala/chisel/Printf.scala new file mode 100644 index 00000000..27b72815 --- /dev/null +++ b/chiselFrontend/src/main/scala/chisel/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/chisel/Reg.scala b/chiselFrontend/src/main/scala/chisel/Reg.scala new file mode 100644 index 00000000..0ed320d7 --- /dev/null +++ b/chiselFrontend/src/main/scala/chisel/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/chisel/SeqUtils.scala b/chiselFrontend/src/main/scala/chisel/SeqUtils.scala new file mode 100644 index 00000000..da75edae --- /dev/null +++ b/chiselFrontend/src/main/scala/chisel/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/chisel/When.scala b/chiselFrontend/src/main/scala/chisel/When.scala new file mode 100644 index 00000000..37c59f24 --- /dev/null +++ b/chiselFrontend/src/main/scala/chisel/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/chisel/internal/Builder.scala b/chiselFrontend/src/main/scala/chisel/internal/Builder.scala new file mode 100644 index 00000000..bacde365 --- /dev/null +++ b/chiselFrontend/src/main/scala/chisel/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 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 new file mode 100644 index 00000000..256a6d7f --- /dev/null +++ b/chiselFrontend/src/main/scala/chisel/internal/Error.scala @@ -0,0 +1,91 @@ +// See LICENSE for license details. + +package chisel.internal + +import scala.collection.mutable.ArrayBuffer + +import chisel._ + +class ChiselException(message: String, cause: Throwable) extends Exception(message, cause) + +private[chisel] object throwException { + def apply(s: String, t: Throwable = null): Nothing = + throw new ChiselException(s, t) +} + +/** Records and reports runtime errors and warnings. */ +private[chisel] class ErrorLog { + def hasErrors: Boolean = errors.exists(_.isFatal) + + /** Log an error message */ + def error(m: => String): Unit = + errors += new Error(m, getUserLineNumber) + + /** Log a warning message */ + def warning(m: => String): Unit = + errors += new Warning(m, getUserLineNumber) + + /** Emit an informational message */ + def info(m: String): Unit = + println(new Info("[%2.3f] %s".format(elapsedTime/1e3, m), None)) // scalastyle:ignore regex + + /** Prints error messages generated by Chisel at runtime. */ + def report(): Unit = errors foreach println // scalastyle:ignore regex + + /** Throw an exception if any errors have yet occurred. */ + def checkpoint(): Unit = if(hasErrors) { + import Console._ + throwException(errors.map(_ + "\n").reduce(_ + _) + + UNDERLINED + "CODE HAS " + errors.filter(_.isFatal).length + RESET + + UNDERLINED + " " + RED + "ERRORS" + RESET + + UNDERLINED + " and " + errors.filterNot(_.isFatal).length + RESET + + UNDERLINED + " " + YELLOW + "WARNINGS" + RESET) + } + + private def findFirstUserFrame(stack: Array[StackTraceElement]): Option[StackTraceElement] = { + def isUserCode(ste: StackTraceElement): Boolean = { + def isUserModule(c: Class[_]): Boolean = + c != null && (c == classOf[Module] || isUserModule(c.getSuperclass)) + isUserModule(Class.forName(ste.getClassName)) + } + + stack.indexWhere(isUserCode) match { + case x if x < 0 => None + case x => Some(stack(x)) + } + } + + private def getUserLineNumber = + findFirstUserFrame(Thread.currentThread().getStackTrace) + + private val errors = ArrayBuffer[LogEntry]() + + private val startTime = System.currentTimeMillis + private def elapsedTime: Long = System.currentTimeMillis - startTime +} + +private abstract class LogEntry(msg: => String, line: Option[StackTraceElement]) { + def isFatal: Boolean = false + def format: String + + override def toString: String = line match { + case Some(l) => s"${format} ${l.getFileName}:${l.getLineNumber}: ${msg} in class ${l.getClassName}" + case None => s"${format} ${msg}" + } + + protected def tag(name: String, color: String): String = + s"[${color}${name}${Console.RESET}]" +} + +private class Error(msg: => String, line: Option[StackTraceElement]) extends LogEntry(msg, line) { + override def isFatal: Boolean = true + def format: String = tag("error", Console.RED) +} + +private class Warning(msg: => String, line: Option[StackTraceElement]) extends LogEntry(msg, line) { + def format: String = tag("warn", Console.YELLOW) +} + +private class Info(msg: => String, line: Option[StackTraceElement]) extends LogEntry(msg, line) { + def format: String = tag("info", Console.MAGENTA) +} diff --git a/chiselFrontend/src/main/scala/chisel/internal/SourceInfo.scala b/chiselFrontend/src/main/scala/chisel/internal/SourceInfo.scala new file mode 100644 index 00000000..c20bd130 --- /dev/null +++ b/chiselFrontend/src/main/scala/chisel/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/chisel/internal/firrtl/IR.scala b/chiselFrontend/src/main/scala/chisel/internal/firrtl/IR.scala new file mode 100644 index 00000000..9c1ce98e --- /dev/null +++ b/chiselFrontend/src/main/scala/chisel/internal/firrtl/IR.scala @@ -0,0 +1,189 @@ +// 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]) -- cgit v1.2.3 From 66301b9042530a5265c18c97a0dab9022a0efc50 Mon Sep 17 00:00:00 2001 From: ducky Date: Wed, 1 Jun 2016 12:17:25 -0700 Subject: Move chisel/... to chisel/core/..., make chisel/compatibility package/folder, move more things into utils --- .../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/core/Aggregate.scala | 377 ++++++++++ .../src/main/scala/chisel/core/Assert.scala | 73 ++ .../src/main/scala/chisel/core/Bits.scala | 756 +++++++++++++++++++++ .../src/main/scala/chisel/core/BlackBox.scala | 55 ++ .../src/main/scala/chisel/core/Data.scala | 161 +++++ .../src/main/scala/chisel/core/Mem.scala | 134 ++++ .../src/main/scala/chisel/core/Module.scala | 119 ++++ .../src/main/scala/chisel/core/Printf.scala | 36 + .../src/main/scala/chisel/core/Reg.scala | 71 ++ .../src/main/scala/chisel/core/SeqUtils.scala | 59 ++ .../src/main/scala/chisel/core/When.scala | 59 ++ 22 files changed, 1900 insertions(+), 1900 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 create mode 100644 chiselFrontend/src/main/scala/chisel/core/Aggregate.scala create mode 100644 chiselFrontend/src/main/scala/chisel/core/Assert.scala create mode 100644 chiselFrontend/src/main/scala/chisel/core/Bits.scala create mode 100644 chiselFrontend/src/main/scala/chisel/core/BlackBox.scala create mode 100644 chiselFrontend/src/main/scala/chisel/core/Data.scala create mode 100644 chiselFrontend/src/main/scala/chisel/core/Mem.scala create mode 100644 chiselFrontend/src/main/scala/chisel/core/Module.scala create mode 100644 chiselFrontend/src/main/scala/chisel/core/Printf.scala create mode 100644 chiselFrontend/src/main/scala/chisel/core/Reg.scala create mode 100644 chiselFrontend/src/main/scala/chisel/core/SeqUtils.scala create mode 100644 chiselFrontend/src/main/scala/chisel/core/When.scala (limited to 'chiselFrontend/src') diff --git a/chiselFrontend/src/main/scala/chisel/Aggregate.scala b/chiselFrontend/src/main/scala/chisel/Aggregate.scala deleted file mode 100644 index 4f3f3de0..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 0d660bc3..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 8ec7c1b9..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 1dabc18f..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 c08adf9d..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 5fd8b81e..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 f7f8c0b5..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 27b72815..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 0ed320d7..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 da75edae..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 37c59f24..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/core/Aggregate.scala b/chiselFrontend/src/main/scala/chisel/core/Aggregate.scala new file mode 100644 index 00000000..4f3f3de0 --- /dev/null +++ b/chiselFrontend/src/main/scala/chisel/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/chisel/core/Assert.scala b/chiselFrontend/src/main/scala/chisel/core/Assert.scala new file mode 100644 index 00000000..0d660bc3 --- /dev/null +++ b/chiselFrontend/src/main/scala/chisel/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/chisel/core/Bits.scala b/chiselFrontend/src/main/scala/chisel/core/Bits.scala new file mode 100644 index 00000000..8ec7c1b9 --- /dev/null +++ b/chiselFrontend/src/main/scala/chisel/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/chisel/core/BlackBox.scala b/chiselFrontend/src/main/scala/chisel/core/BlackBox.scala new file mode 100644 index 00000000..1dabc18f --- /dev/null +++ b/chiselFrontend/src/main/scala/chisel/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/chisel/core/Data.scala b/chiselFrontend/src/main/scala/chisel/core/Data.scala new file mode 100644 index 00000000..c08adf9d --- /dev/null +++ b/chiselFrontend/src/main/scala/chisel/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/chisel/core/Mem.scala b/chiselFrontend/src/main/scala/chisel/core/Mem.scala new file mode 100644 index 00000000..5fd8b81e --- /dev/null +++ b/chiselFrontend/src/main/scala/chisel/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/chisel/core/Module.scala b/chiselFrontend/src/main/scala/chisel/core/Module.scala new file mode 100644 index 00000000..f7f8c0b5 --- /dev/null +++ b/chiselFrontend/src/main/scala/chisel/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/chisel/core/Printf.scala b/chiselFrontend/src/main/scala/chisel/core/Printf.scala new file mode 100644 index 00000000..27b72815 --- /dev/null +++ b/chiselFrontend/src/main/scala/chisel/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/chisel/core/Reg.scala b/chiselFrontend/src/main/scala/chisel/core/Reg.scala new file mode 100644 index 00000000..0ed320d7 --- /dev/null +++ b/chiselFrontend/src/main/scala/chisel/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/chisel/core/SeqUtils.scala b/chiselFrontend/src/main/scala/chisel/core/SeqUtils.scala new file mode 100644 index 00000000..da75edae --- /dev/null +++ b/chiselFrontend/src/main/scala/chisel/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/chisel/core/When.scala b/chiselFrontend/src/main/scala/chisel/core/When.scala new file mode 100644 index 00000000..37c59f24 --- /dev/null +++ b/chiselFrontend/src/main/scala/chisel/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)) +} -- cgit v1.2.3 From 69c984607e87cb62c82c99056b2664f11b968267 Mon Sep 17 00:00:00 2001 From: ducky Date: Wed, 1 Jun 2016 12:46:05 -0700 Subject: Package split chisel core --- .../src/main/scala/chisel/core/Aggregate.scala | 18 ++++++------ .../src/main/scala/chisel/core/Assert.scala | 10 +++---- .../src/main/scala/chisel/core/Bits.scala | 32 +++++++++++----------- .../src/main/scala/chisel/core/BlackBox.scala | 14 +++++----- .../src/main/scala/chisel/core/Data.scala | 26 +++++++++--------- .../src/main/scala/chisel/core/Mem.scala | 10 +++---- .../src/main/scala/chisel/core/Module.scala | 24 ++++++++-------- .../src/main/scala/chisel/core/Printf.scala | 12 ++++---- .../src/main/scala/chisel/core/Reg.scala | 12 ++++---- .../src/main/scala/chisel/core/SeqUtils.scala | 4 +-- .../src/main/scala/chisel/core/When.scala | 10 +++---- .../src/main/scala/chisel/internal/Builder.scala | 1 + .../src/main/scala/chisel/internal/Error.scala | 2 +- .../src/main/scala/chisel/internal/firrtl/IR.scala | 1 + 14 files changed, 89 insertions(+), 87 deletions(-) (limited to 'chiselFrontend/src') diff --git a/chiselFrontend/src/main/scala/chisel/core/Aggregate.scala b/chiselFrontend/src/main/scala/chisel/core/Aggregate.scala index 4f3f3de0..38a42fea 100644 --- a/chiselFrontend/src/main/scala/chisel/core/Aggregate.scala +++ b/chiselFrontend/src/main/scala/chisel/core/Aggregate.scala @@ -1,21 +1,21 @@ // See LICENSE for license details. -package chisel +package chisel.core 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} +import chisel.internal._ +import chisel.internal.Builder.pushCommand +import chisel.internal.firrtl._ +import chisel.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 + private[core] def cloneTypeWidth(width: Width): this.type = cloneType def width: Width = flatten.map(_.width).reduce(_ + _) } @@ -315,7 +315,7 @@ class Bundle extends Aggregate(NO_DIR) { /** Returns a list of elements in this Bundle. */ - private[chisel] lazy val namedElts = { + private[core] lazy val namedElts = { val nameMap = LinkedHashMap[String, Data]() val seen = HashSet[Data]() for (m <- getClass.getMethods.sortWith(_.getName < _.getName)) { @@ -339,7 +339,7 @@ class Bundle extends Aggregate(NO_DIR) { 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 = + private[core] 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)) } @@ -372,6 +372,6 @@ class Bundle extends Aggregate(NO_DIR) { } } -private[chisel] object Bundle { +private[core] object Bundle { val keywords = List("flip", "asInput", "asOutput", "cloneType", "toBits") } diff --git a/chiselFrontend/src/main/scala/chisel/core/Assert.scala b/chiselFrontend/src/main/scala/chisel/core/Assert.scala index 0d660bc3..00cb00f4 100644 --- a/chiselFrontend/src/main/scala/chisel/core/Assert.scala +++ b/chiselFrontend/src/main/scala/chisel/core/Assert.scala @@ -1,14 +1,14 @@ // See LICENSE for license details. -package chisel +package chisel.core import scala.reflect.macros.blackbox.Context import scala.language.experimental.macros -import internal._ -import internal.Builder.pushCommand -import internal.firrtl._ -import internal.sourceinfo.SourceInfo +import chisel.internal._ +import chisel.internal.Builder.pushCommand +import chisel.internal.firrtl._ +import chisel.internal.sourceinfo.SourceInfo object assert { // scalastyle:ignore object.name /** Checks for a condition to be valid in the circuit at all times. If the diff --git a/chiselFrontend/src/main/scala/chisel/core/Bits.scala b/chiselFrontend/src/main/scala/chisel/core/Bits.scala index 8ec7c1b9..38e71f8d 100644 --- a/chiselFrontend/src/main/scala/chisel/core/Bits.scala +++ b/chiselFrontend/src/main/scala/chisel/core/Bits.scala @@ -1,15 +1,15 @@ // See LICENSE for license details. -package chisel +package chisel.core import scala.language.experimental.macros -import internal._ -import internal.Builder.pushOp -import internal.firrtl._ -import internal.sourceinfo.{SourceInfo, DeprecatedSourceInfo, SourceInfoTransform, SourceInfoWhiteboxTransform, +import chisel.internal._ +import chisel.internal.Builder.pushOp +import chisel.internal.firrtl._ +import chisel.internal.sourceinfo.{SourceInfo, DeprecatedSourceInfo, SourceInfoTransform, SourceInfoWhiteboxTransform, UIntTransform, MuxTransform} -import firrtl.PrimOp._ +import chisel.internal.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. @@ -118,16 +118,16 @@ sealed abstract class Bits(dirArg: Direction, width: Width, override val litArg: 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 = + private[core] 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 = + private[core] 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 = + private[core] 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 = + private[core] 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 = + private[core] def redop(sourceInfo: SourceInfo, op: PrimOp): Bool = pushOp(DefPrim(sourceInfo, Bool(), op, this.ref)) /** Returns this wire zero padded up to the specified width. @@ -356,9 +356,9 @@ abstract trait Num[T <: Data] { /** 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) +sealed class UInt private[core] (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 = + private[core] override def cloneTypeWidth(w: Width): this.type = new UInt(dir, w).asInstanceOf[this.type] private[chisel] def toType = s"UInt$width" @@ -482,7 +482,7 @@ sealed class UInt private[chisel] (dir: Direction, width: Width, lit: Option[ULi } // This is currently a factory because both Bits and UInt inherit it. -private[chisel] sealed trait UIntFactory { +private[core] 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. */ @@ -535,7 +535,7 @@ 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 = + private[core] override def cloneTypeWidth(w: Width): this.type = new SInt(dir, w).asInstanceOf[this.type] private[chisel] def toType = s"SInt$width" @@ -666,7 +666,7 @@ object SInt { /** 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 = { + private[core] override def cloneTypeWidth(w: Width): this.type = { require(!w.known || w.get == 1) new Bool(dir).asInstanceOf[this.type] } diff --git a/chiselFrontend/src/main/scala/chisel/core/BlackBox.scala b/chiselFrontend/src/main/scala/chisel/core/BlackBox.scala index 1dabc18f..2126ebce 100644 --- a/chiselFrontend/src/main/scala/chisel/core/BlackBox.scala +++ b/chiselFrontend/src/main/scala/chisel/core/BlackBox.scala @@ -1,10 +1,10 @@ // See LICENSE for license details. -package chisel +package chisel.core -import internal.Builder.pushCommand -import internal.firrtl.{ModuleIO, DefInvalid} -import internal.sourceinfo.SourceInfo +import chisel.internal.Builder.pushCommand +import chisel.internal.firrtl.{ModuleIO, DefInvalid} +import chisel.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 @@ -24,10 +24,10 @@ abstract class BlackBox extends Module { // 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 + override private[core] def ports = io.elements.toSeq // Do not do reflective naming of internal signals, just name io - override private[chisel] def setRefs(): this.type = { + override private[core] def setRefs(): this.type = { for ((name, port) <- ports) { port.setRef(ModuleIO(this, _namespace.name(name))) } @@ -40,7 +40,7 @@ abstract class BlackBox extends Module { // 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 { + override private[core] def setupInParent(implicit sourceInfo: SourceInfo): this.type = _parent match { case Some(p) => { // Just init instance inputs for((_,port) <- ports) pushCommand(DefInvalid(sourceInfo, port.ref)) diff --git a/chiselFrontend/src/main/scala/chisel/core/Data.scala b/chiselFrontend/src/main/scala/chisel/core/Data.scala index c08adf9d..077c4893 100644 --- a/chiselFrontend/src/main/scala/chisel/core/Data.scala +++ b/chiselFrontend/src/main/scala/chisel/core/Data.scala @@ -1,13 +1,13 @@ // See LICENSE for license details. -package chisel +package chisel.core import scala.language.experimental.macros -import internal._ -import internal.Builder.pushCommand -import internal.firrtl._ -import internal.sourceinfo.{SourceInfo, DeprecatedSourceInfo, UnlocatableSourceInfo, WireTransform, SourceInfoTransform} +import chisel.internal._ +import chisel.internal.Builder.pushCommand +import chisel.internal.firrtl._ +import chisel.internal.sourceinfo.{SourceInfo, DeprecatedSourceInfo, UnlocatableSourceInfo, WireTransform, SourceInfoTransform} sealed abstract class Direction(name: String) { override def toString: String = name @@ -38,9 +38,9 @@ abstract class Data(dirArg: Direction) extends HasId { // 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[core] def isFlip = isFlipVar - private[chisel] def overrideDirection(newDir: Direction => Direction, + private[core] def overrideDirection(newDir: Direction => Direction, newFlip: Boolean => Boolean): this.type = { this.isFlipVar = newFlip(this.isFlipVar) for (field <- this.flatten) @@ -51,15 +51,15 @@ abstract class Data(dirArg: Direction) extends HasId { 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 = + private[core] 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 = + private[core] 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 = + private[core] def bulkConnect(that: Data)(implicit sourceInfo: SourceInfo): Unit = pushCommand(BulkConnect(sourceInfo, this.lref, that.lref)) - private[chisel] def lref: Node = Node(this) + private[core] 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[core] def cloneTypeWidth(width: Width): this.type private[chisel] def toType: String def := (that: Data)(implicit sourceInfo: SourceInfo): Unit = this badConnect that @@ -151,7 +151,7 @@ object Clock { 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[core] def cloneTypeWidth(width: Width): this.type = cloneType private[chisel] def toType = "Clock" override def := (that: Data)(implicit sourceInfo: SourceInfo): Unit = that match { diff --git a/chiselFrontend/src/main/scala/chisel/core/Mem.scala b/chiselFrontend/src/main/scala/chisel/core/Mem.scala index 5fd8b81e..a2df2910 100644 --- a/chiselFrontend/src/main/scala/chisel/core/Mem.scala +++ b/chiselFrontend/src/main/scala/chisel/core/Mem.scala @@ -1,13 +1,13 @@ // See LICENSE for license details. -package chisel +package chisel.core import scala.language.experimental.macros -import internal._ -import internal.Builder.pushCommand -import internal.firrtl._ -import internal.sourceinfo.{SourceInfo, DeprecatedSourceInfo, UnlocatableSourceInfo, MemTransform} +import chisel.internal._ +import chisel.internal.Builder.pushCommand +import chisel.internal.firrtl._ +import chisel.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") diff --git a/chiselFrontend/src/main/scala/chisel/core/Module.scala b/chiselFrontend/src/main/scala/chisel/core/Module.scala index f7f8c0b5..1de3efe5 100644 --- a/chiselFrontend/src/main/scala/chisel/core/Module.scala +++ b/chiselFrontend/src/main/scala/chisel/core/Module.scala @@ -1,15 +1,15 @@ // See LICENSE for license details. -package chisel +package chisel.core 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} +import chisel.internal._ +import chisel.internal.Builder.pushCommand +import chisel.internal.Builder.dynamicContext +import chisel.internal.firrtl._ +import chisel.internal.sourceinfo.{SourceInfo, InstTransform, UnlocatableSourceInfo} object Module { /** A wrapper method that all Module instantiations must be wrapped in @@ -52,9 +52,9 @@ extends HasId { 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[core] val _namespace = Builder.globalNamespace.child private[chisel] val _commands = ArrayBuffer[Command]() - private[chisel] val _ids = ArrayBuffer[HasId]() + private[core] val _ids = ArrayBuffer[HasId]() dynamicContext.currentModule = Some(this) /** Name of the instance. */ @@ -69,16 +69,16 @@ extends HasId { private[chisel] def addId(d: HasId) { _ids += d } - private[chisel] def ports: Seq[(String,Data)] = Vector( + private[core] def ports: Seq[(String,Data)] = Vector( ("clk", clock), ("reset", reset), ("io", io) ) - private[chisel] def computePorts = for((name, port) <- ports) yield { + private[core] 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 = { + private[core] def setupInParent(implicit sourceInfo: SourceInfo): this.type = { _parent match { case Some(p) => { pushCommand(DefInvalid(sourceInfo, io.ref)) // init instance inputs @@ -90,7 +90,7 @@ extends HasId { } } - private[chisel] def setRefs(): this.type = { + private[core] def setRefs(): this.type = { for ((name, port) <- ports) { port.setRef(ModuleIO(this, _namespace.name(name))) } diff --git a/chiselFrontend/src/main/scala/chisel/core/Printf.scala b/chiselFrontend/src/main/scala/chisel/core/Printf.scala index 27b72815..a7970816 100644 --- a/chiselFrontend/src/main/scala/chisel/core/Printf.scala +++ b/chiselFrontend/src/main/scala/chisel/core/Printf.scala @@ -1,13 +1,13 @@ // See LICENSE for license details. -package chisel +package chisel.core import scala.language.experimental.macros -import internal._ -import internal.Builder.pushCommand -import internal.firrtl._ -import internal.sourceinfo.SourceInfo +import chisel.internal._ +import chisel.internal.Builder.pushCommand +import chisel.internal.firrtl._ +import chisel.internal.sourceinfo.SourceInfo object printf { // scalastyle:ignore object.name /** Prints a message in simulation. @@ -29,7 +29,7 @@ object printf { // scalastyle:ignore object.name } } - private[chisel] def printfWithoutReset(fmt: String, data: Bits*)(implicit sourceInfo: SourceInfo) { + private[core] 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/core/Reg.scala b/chiselFrontend/src/main/scala/chisel/core/Reg.scala index 0ed320d7..78461334 100644 --- a/chiselFrontend/src/main/scala/chisel/core/Reg.scala +++ b/chiselFrontend/src/main/scala/chisel/core/Reg.scala @@ -1,14 +1,14 @@ // See LICENSE for license details. -package chisel +package chisel.core -import internal._ -import internal.Builder.pushCommand -import internal.firrtl._ -import internal.sourceinfo.{SourceInfo, UnlocatableSourceInfo} +import chisel.internal._ +import chisel.internal.Builder.pushCommand +import chisel.internal.firrtl._ +import chisel.internal.sourceinfo.{SourceInfo, UnlocatableSourceInfo} object Reg { - private[chisel] def makeType[T <: Data](t: T = null, next: T = null, init: T = null): T = { + private[core] 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) { diff --git a/chiselFrontend/src/main/scala/chisel/core/SeqUtils.scala b/chiselFrontend/src/main/scala/chisel/core/SeqUtils.scala index da75edae..e31119a5 100644 --- a/chiselFrontend/src/main/scala/chisel/core/SeqUtils.scala +++ b/chiselFrontend/src/main/scala/chisel/core/SeqUtils.scala @@ -1,10 +1,10 @@ // See LICENSE for license details. -package chisel +package chisel.core import scala.language.experimental.macros -import internal.sourceinfo.{SourceInfo, SourceInfoTransform} +import chisel.internal.sourceinfo.{SourceInfo, SourceInfoTransform} private[chisel] object SeqUtils { /** Equivalent to Cat(r(n-1), ..., r(0)) */ diff --git a/chiselFrontend/src/main/scala/chisel/core/When.scala b/chiselFrontend/src/main/scala/chisel/core/When.scala index 37c59f24..5d484313 100644 --- a/chiselFrontend/src/main/scala/chisel/core/When.scala +++ b/chiselFrontend/src/main/scala/chisel/core/When.scala @@ -1,13 +1,13 @@ // See LICENSE for license details. -package chisel +package chisel.core import scala.language.experimental.macros -import internal._ -import internal.Builder.pushCommand -import internal.firrtl._ -import internal.sourceinfo.{SourceInfo} +import chisel.internal._ +import chisel.internal.Builder.pushCommand +import chisel.internal.firrtl._ +import chisel.internal.sourceinfo.{SourceInfo} object when { // scalastyle:ignore object.name /** Create a `when` condition block, where whether a block of logic is diff --git a/chiselFrontend/src/main/scala/chisel/internal/Builder.scala b/chiselFrontend/src/main/scala/chisel/internal/Builder.scala index bacde365..9c0a3514 100644 --- a/chiselFrontend/src/main/scala/chisel/internal/Builder.scala +++ b/chiselFrontend/src/main/scala/chisel/internal/Builder.scala @@ -6,6 +6,7 @@ import scala.util.DynamicVariable import scala.collection.mutable.{ArrayBuffer, HashMap} import chisel._ +import core._ import firrtl._ private[chisel] class Namespace(parent: Option[Namespace], keywords: Set[String]) { diff --git a/chiselFrontend/src/main/scala/chisel/internal/Error.scala b/chiselFrontend/src/main/scala/chisel/internal/Error.scala index 256a6d7f..f0481dc4 100644 --- a/chiselFrontend/src/main/scala/chisel/internal/Error.scala +++ b/chiselFrontend/src/main/scala/chisel/internal/Error.scala @@ -4,7 +4,7 @@ package chisel.internal import scala.collection.mutable.ArrayBuffer -import chisel._ +import chisel.core._ class ChiselException(message: String, cause: Throwable) extends Exception(message, cause) diff --git a/chiselFrontend/src/main/scala/chisel/internal/firrtl/IR.scala b/chiselFrontend/src/main/scala/chisel/internal/firrtl/IR.scala index 9c1ce98e..70e9938b 100644 --- a/chiselFrontend/src/main/scala/chisel/internal/firrtl/IR.scala +++ b/chiselFrontend/src/main/scala/chisel/internal/firrtl/IR.scala @@ -3,6 +3,7 @@ package chisel.internal.firrtl import chisel._ +import core._ import chisel.internal._ import chisel.internal.sourceinfo.{SourceInfo, NoSourceInfo} -- cgit v1.2.3 From 68447044e8eba5c8f525639130f1a347677ff543 Mon Sep 17 00:00:00 2001 From: ducky Date: Wed, 1 Jun 2016 13:00:40 -0700 Subject: Move deprecated debug into compatibility --- chiselFrontend/src/main/scala/chisel/core/Data.scala | 5 ----- 1 file changed, 5 deletions(-) (limited to 'chiselFrontend/src') diff --git a/chiselFrontend/src/main/scala/chisel/core/Data.scala b/chiselFrontend/src/main/scala/chisel/core/Data.scala index 077c4893..cae38144 100644 --- a/chiselFrontend/src/main/scala/chisel/core/Data.scala +++ b/chiselFrontend/src/main/scala/chisel/core/Data.scala @@ -17,11 +17,6 @@ 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, !_) -- cgit v1.2.3 From b5a534914795d9d17f4dfe623525f1b804e4c60f Mon Sep 17 00:00:00 2001 From: Andrew Waterman Date: Wed, 15 Jun 2016 10:54:15 -0700 Subject: Generate better node names when names collide (#221) Rather than using a global counter, memoize the last returned value for colliding names to generate smaller sequence numbers.--- .../src/main/scala/chisel/internal/Builder.scala | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) (limited to 'chiselFrontend/src') diff --git a/chiselFrontend/src/main/scala/chisel/internal/Builder.scala b/chiselFrontend/src/main/scala/chisel/internal/Builder.scala index 9c0a3514..01628105 100644 --- a/chiselFrontend/src/main/scala/chisel/internal/Builder.scala +++ b/chiselFrontend/src/main/scala/chisel/internal/Builder.scala @@ -10,21 +10,26 @@ import core._ import 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}" } + private val names = collection.mutable.HashMap[String, Long]() + for (keyword <- keywords) + names(keyword) = 1 + + private def rename(n: String): String = { + val index = names.getOrElse(n, 1L) + val tryName = s"${n}_${index}" + names(n) = index + 1 + if (this contains tryName) rename(n) else tryName + } def contains(elem: String): Boolean = { - keywords.contains(elem) || names.contains(elem) || - parent.map(_ contains elem).getOrElse(false) + names.contains(elem) || parent.map(_ contains elem).getOrElse(false) } def name(elem: String): String = { if (this contains elem) { name(rename(elem)) } else { - names += elem + names(elem) = 1 elem } } -- cgit v1.2.3 From d408d73a171535bd7c2ba9d0037c194022b8a62f Mon Sep 17 00:00:00 2001 From: Jim Lawson Date: Mon, 20 Jun 2016 11:08:46 -0700 Subject: Rename chisel3 package. --- .../src/main/scala/chisel/core/Aggregate.scala | 377 ---------- .../src/main/scala/chisel/core/Assert.scala | 73 -- .../src/main/scala/chisel/core/Bits.scala | 756 --------------------- .../src/main/scala/chisel/core/BlackBox.scala | 55 -- .../src/main/scala/chisel/core/Data.scala | 156 ----- .../src/main/scala/chisel/core/Mem.scala | 134 ---- .../src/main/scala/chisel/core/Module.scala | 119 ---- .../src/main/scala/chisel/core/Printf.scala | 36 - .../src/main/scala/chisel/core/Reg.scala | 71 -- .../src/main/scala/chisel/core/SeqUtils.scala | 59 -- .../src/main/scala/chisel/core/When.scala | 59 -- .../src/main/scala/chisel/internal/Builder.scala | 129 ---- .../src/main/scala/chisel/internal/Error.scala | 91 --- .../main/scala/chisel/internal/SourceInfo.scala | 51 -- .../src/main/scala/chisel/internal/firrtl/IR.scala | 190 ------ .../src/main/scala/chisel3/core/Aggregate.scala | 377 ++++++++++ .../src/main/scala/chisel3/core/Assert.scala | 73 ++ .../src/main/scala/chisel3/core/Bits.scala | 756 +++++++++++++++++++++ .../src/main/scala/chisel3/core/BlackBox.scala | 55 ++ .../src/main/scala/chisel3/core/Data.scala | 156 +++++ .../src/main/scala/chisel3/core/Mem.scala | 134 ++++ .../src/main/scala/chisel3/core/Module.scala | 119 ++++ .../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 | 129 ++++ .../src/main/scala/chisel3/internal/Error.scala | 91 +++ .../main/scala/chisel3/internal/SourceInfo.scala | 51 ++ .../main/scala/chisel3/internal/firrtl/IR.scala | 190 ++++++ 30 files changed, 2356 insertions(+), 2356 deletions(-) delete mode 100644 chiselFrontend/src/main/scala/chisel/core/Aggregate.scala delete mode 100644 chiselFrontend/src/main/scala/chisel/core/Assert.scala delete mode 100644 chiselFrontend/src/main/scala/chisel/core/Bits.scala delete mode 100644 chiselFrontend/src/main/scala/chisel/core/BlackBox.scala delete mode 100644 chiselFrontend/src/main/scala/chisel/core/Data.scala delete mode 100644 chiselFrontend/src/main/scala/chisel/core/Mem.scala delete mode 100644 chiselFrontend/src/main/scala/chisel/core/Module.scala delete mode 100644 chiselFrontend/src/main/scala/chisel/core/Printf.scala delete mode 100644 chiselFrontend/src/main/scala/chisel/core/Reg.scala delete mode 100644 chiselFrontend/src/main/scala/chisel/core/SeqUtils.scala delete mode 100644 chiselFrontend/src/main/scala/chisel/core/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/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/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 (limited to 'chiselFrontend/src') diff --git a/chiselFrontend/src/main/scala/chisel/core/Aggregate.scala b/chiselFrontend/src/main/scala/chisel/core/Aggregate.scala deleted file mode 100644 index 38a42fea..00000000 --- a/chiselFrontend/src/main/scala/chisel/core/Aggregate.scala +++ /dev/null @@ -1,377 +0,0 @@ -// See LICENSE for license details. - -package chisel.core - -import scala.collection.immutable.ListMap -import scala.collection.mutable.{ArrayBuffer, HashSet, LinkedHashMap} -import scala.language.experimental.macros - -import chisel.internal._ -import chisel.internal.Builder.pushCommand -import chisel.internal.firrtl._ -import chisel.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[core] 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[core] 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[core] 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[core] object Bundle { - val keywords = List("flip", "asInput", "asOutput", "cloneType", "toBits") -} diff --git a/chiselFrontend/src/main/scala/chisel/core/Assert.scala b/chiselFrontend/src/main/scala/chisel/core/Assert.scala deleted file mode 100644 index 00cb00f4..00000000 --- a/chiselFrontend/src/main/scala/chisel/core/Assert.scala +++ /dev/null @@ -1,73 +0,0 @@ -// See LICENSE for license details. - -package chisel.core - -import scala.reflect.macros.blackbox.Context -import scala.language.experimental.macros - -import chisel.internal._ -import chisel.internal.Builder.pushCommand -import chisel.internal.firrtl._ -import chisel.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/core/Bits.scala b/chiselFrontend/src/main/scala/chisel/core/Bits.scala deleted file mode 100644 index 38e71f8d..00000000 --- a/chiselFrontend/src/main/scala/chisel/core/Bits.scala +++ /dev/null @@ -1,756 +0,0 @@ -// See LICENSE for license details. - -package chisel.core - -import scala.language.experimental.macros - -import chisel.internal._ -import chisel.internal.Builder.pushOp -import chisel.internal.firrtl._ -import chisel.internal.sourceinfo.{SourceInfo, DeprecatedSourceInfo, SourceInfoTransform, SourceInfoWhiteboxTransform, - UIntTransform, MuxTransform} -import chisel.internal.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[core] def unop[T <: Data](sourceInfo: SourceInfo, dest: T, op: PrimOp): T = - pushOp(DefPrim(sourceInfo, dest, op, this.ref)) - private[core] def binop[T <: Data](sourceInfo: SourceInfo, dest: T, op: PrimOp, other: BigInt): T = - pushOp(DefPrim(sourceInfo, dest, op, this.ref, ILit(other))) - private[core] def binop[T <: Data](sourceInfo: SourceInfo, dest: T, op: PrimOp, other: Bits): T = - pushOp(DefPrim(sourceInfo, dest, op, this.ref, other.ref)) - - private[core] def compop(sourceInfo: SourceInfo, op: PrimOp, other: Bits): Bool = - pushOp(DefPrim(sourceInfo, Bool(), op, this.ref, other.ref)) - private[core] 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[core] (dir: Direction, width: Width, lit: Option[ULit] = None) - extends Bits(dir, width, lit) with Num[UInt] { - private[core] 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[core] 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[core] 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[core] 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/core/BlackBox.scala b/chiselFrontend/src/main/scala/chisel/core/BlackBox.scala deleted file mode 100644 index 2126ebce..00000000 --- a/chiselFrontend/src/main/scala/chisel/core/BlackBox.scala +++ /dev/null @@ -1,55 +0,0 @@ -// See LICENSE for license details. - -package chisel.core - -import chisel.internal.Builder.pushCommand -import chisel.internal.firrtl.{ModuleIO, DefInvalid} -import chisel.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[core] def ports = io.elements.toSeq - - // Do not do reflective naming of internal signals, just name io - override private[core] 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[core] 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/core/Data.scala b/chiselFrontend/src/main/scala/chisel/core/Data.scala deleted file mode 100644 index cae38144..00000000 --- a/chiselFrontend/src/main/scala/chisel/core/Data.scala +++ /dev/null @@ -1,156 +0,0 @@ -// See LICENSE for license details. - -package chisel.core - -import scala.language.experimental.macros - -import chisel.internal._ -import chisel.internal.Builder.pushCommand -import chisel.internal.firrtl._ -import chisel.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 } - -/** 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[core] def isFlip = isFlipVar - - private[core] 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[core] def badConnect(that: Data)(implicit sourceInfo: SourceInfo): Unit = - throwException(s"cannot connect ${this} and ${that}") - private[core] def connect(that: Data)(implicit sourceInfo: SourceInfo): Unit = - pushCommand(Connect(sourceInfo, this.lref, that.ref)) - private[core] def bulkConnect(that: Data)(implicit sourceInfo: SourceInfo): Unit = - pushCommand(BulkConnect(sourceInfo, this.lref, that.lref)) - private[core] def lref: Node = Node(this) - private[chisel] def ref: Arg = if (isLit) litArg.get else lref - private[core] 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[core] 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/core/Mem.scala b/chiselFrontend/src/main/scala/chisel/core/Mem.scala deleted file mode 100644 index a2df2910..00000000 --- a/chiselFrontend/src/main/scala/chisel/core/Mem.scala +++ /dev/null @@ -1,134 +0,0 @@ -// See LICENSE for license details. - -package chisel.core - -import scala.language.experimental.macros - -import chisel.internal._ -import chisel.internal.Builder.pushCommand -import chisel.internal.firrtl._ -import chisel.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/core/Module.scala b/chiselFrontend/src/main/scala/chisel/core/Module.scala deleted file mode 100644 index 1de3efe5..00000000 --- a/chiselFrontend/src/main/scala/chisel/core/Module.scala +++ /dev/null @@ -1,119 +0,0 @@ -// See LICENSE for license details. - -package chisel.core - -import scala.collection.mutable.{ArrayBuffer, HashSet} -import scala.language.experimental.macros - -import chisel.internal._ -import chisel.internal.Builder.pushCommand -import chisel.internal.Builder.dynamicContext -import chisel.internal.firrtl._ -import chisel.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[core] val _namespace = Builder.globalNamespace.child - private[chisel] val _commands = ArrayBuffer[Command]() - private[core] 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[core] def ports: Seq[(String,Data)] = Vector( - ("clk", clock), ("reset", reset), ("io", io) - ) - - private[core] 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[core] 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[core] 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/core/Printf.scala b/chiselFrontend/src/main/scala/chisel/core/Printf.scala deleted file mode 100644 index a7970816..00000000 --- a/chiselFrontend/src/main/scala/chisel/core/Printf.scala +++ /dev/null @@ -1,36 +0,0 @@ -// See LICENSE for license details. - -package chisel.core - -import scala.language.experimental.macros - -import chisel.internal._ -import chisel.internal.Builder.pushCommand -import chisel.internal.firrtl._ -import chisel.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[core] 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/core/Reg.scala b/chiselFrontend/src/main/scala/chisel/core/Reg.scala deleted file mode 100644 index 78461334..00000000 --- a/chiselFrontend/src/main/scala/chisel/core/Reg.scala +++ /dev/null @@ -1,71 +0,0 @@ -// See LICENSE for license details. - -package chisel.core - -import chisel.internal._ -import chisel.internal.Builder.pushCommand -import chisel.internal.firrtl._ -import chisel.internal.sourceinfo.{SourceInfo, UnlocatableSourceInfo} - -object Reg { - private[core] 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/core/SeqUtils.scala b/chiselFrontend/src/main/scala/chisel/core/SeqUtils.scala deleted file mode 100644 index e31119a5..00000000 --- a/chiselFrontend/src/main/scala/chisel/core/SeqUtils.scala +++ /dev/null @@ -1,59 +0,0 @@ -// See LICENSE for license details. - -package chisel.core - -import scala.language.experimental.macros - -import chisel.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/core/When.scala b/chiselFrontend/src/main/scala/chisel/core/When.scala deleted file mode 100644 index 5d484313..00000000 --- a/chiselFrontend/src/main/scala/chisel/core/When.scala +++ /dev/null @@ -1,59 +0,0 @@ -// See LICENSE for license details. - -package chisel.core - -import scala.language.experimental.macros - -import chisel.internal._ -import chisel.internal.Builder.pushCommand -import chisel.internal.firrtl._ -import chisel.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 01628105..00000000 --- a/chiselFrontend/src/main/scala/chisel/internal/Builder.scala +++ /dev/null @@ -1,129 +0,0 @@ -// See LICENSE for license details. - -package chisel.internal - -import scala.util.DynamicVariable -import scala.collection.mutable.{ArrayBuffer, HashMap} - -import chisel._ -import core._ -import firrtl._ - -private[chisel] class Namespace(parent: Option[Namespace], keywords: Set[String]) { - private val names = collection.mutable.HashMap[String, Long]() - for (keyword <- keywords) - names(keyword) = 1 - - private def rename(n: String): String = { - val index = names.getOrElse(n, 1L) - val tryName = s"${n}_${index}" - names(n) = index + 1 - if (this contains tryName) rename(n) else tryName - } - - def contains(elem: String): Boolean = { - names.contains(elem) || parent.map(_ contains elem).getOrElse(false) - } - - def name(elem: String): String = { - if (this contains elem) { - name(rename(elem)) - } else { - names(elem) = 1 - 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 f0481dc4..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.core._ - -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 c20bd130..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 70e9938b..00000000 --- a/chiselFrontend/src/main/scala/chisel/internal/firrtl/IR.scala +++ /dev/null @@ -1,190 +0,0 @@ -// See LICENSE for license details. - -package chisel.internal.firrtl - -import chisel._ -import core._ -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..38a42fea --- /dev/null +++ b/chiselFrontend/src/main/scala/chisel3/core/Aggregate.scala @@ -0,0 +1,377 @@ +// See LICENSE for license details. + +package chisel.core + +import scala.collection.immutable.ListMap +import scala.collection.mutable.{ArrayBuffer, HashSet, LinkedHashMap} +import scala.language.experimental.macros + +import chisel.internal._ +import chisel.internal.Builder.pushCommand +import chisel.internal.firrtl._ +import chisel.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[core] 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[core] 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[core] 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[core] 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..00cb00f4 --- /dev/null +++ b/chiselFrontend/src/main/scala/chisel3/core/Assert.scala @@ -0,0 +1,73 @@ +// See LICENSE for license details. + +package chisel.core + +import scala.reflect.macros.blackbox.Context +import scala.language.experimental.macros + +import chisel.internal._ +import chisel.internal.Builder.pushCommand +import chisel.internal.firrtl._ +import chisel.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/Bits.scala b/chiselFrontend/src/main/scala/chisel3/core/Bits.scala new file mode 100644 index 00000000..38e71f8d --- /dev/null +++ b/chiselFrontend/src/main/scala/chisel3/core/Bits.scala @@ -0,0 +1,756 @@ +// See LICENSE for license details. + +package chisel.core + +import scala.language.experimental.macros + +import chisel.internal._ +import chisel.internal.Builder.pushOp +import chisel.internal.firrtl._ +import chisel.internal.sourceinfo.{SourceInfo, DeprecatedSourceInfo, SourceInfoTransform, SourceInfoWhiteboxTransform, + UIntTransform, MuxTransform} +import chisel.internal.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[core] def unop[T <: Data](sourceInfo: SourceInfo, dest: T, op: PrimOp): T = + pushOp(DefPrim(sourceInfo, dest, op, this.ref)) + private[core] def binop[T <: Data](sourceInfo: SourceInfo, dest: T, op: PrimOp, other: BigInt): T = + pushOp(DefPrim(sourceInfo, dest, op, this.ref, ILit(other))) + private[core] def binop[T <: Data](sourceInfo: SourceInfo, dest: T, op: PrimOp, other: Bits): T = + pushOp(DefPrim(sourceInfo, dest, op, this.ref, other.ref)) + + private[core] def compop(sourceInfo: SourceInfo, op: PrimOp, other: Bits): Bool = + pushOp(DefPrim(sourceInfo, Bool(), op, this.ref, other.ref)) + private[core] 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[core] (dir: Direction, width: Width, lit: Option[ULit] = None) + extends Bits(dir, width, lit) with Num[UInt] { + private[core] 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[core] 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[core] 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[core] 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..2126ebce --- /dev/null +++ b/chiselFrontend/src/main/scala/chisel3/core/BlackBox.scala @@ -0,0 +1,55 @@ +// See LICENSE for license details. + +package chisel.core + +import chisel.internal.Builder.pushCommand +import chisel.internal.firrtl.{ModuleIO, DefInvalid} +import chisel.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[core] def ports = io.elements.toSeq + + // Do not do reflective naming of internal signals, just name io + override private[core] 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[core] 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..cae38144 --- /dev/null +++ b/chiselFrontend/src/main/scala/chisel3/core/Data.scala @@ -0,0 +1,156 @@ +// See LICENSE for license details. + +package chisel.core + +import scala.language.experimental.macros + +import chisel.internal._ +import chisel.internal.Builder.pushCommand +import chisel.internal.firrtl._ +import chisel.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 } + +/** 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[core] def isFlip = isFlipVar + + private[core] 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[core] def badConnect(that: Data)(implicit sourceInfo: SourceInfo): Unit = + throwException(s"cannot connect ${this} and ${that}") + private[core] def connect(that: Data)(implicit sourceInfo: SourceInfo): Unit = + pushCommand(Connect(sourceInfo, this.lref, that.ref)) + private[core] def bulkConnect(that: Data)(implicit sourceInfo: SourceInfo): Unit = + pushCommand(BulkConnect(sourceInfo, this.lref, that.lref)) + private[core] def lref: Node = Node(this) + private[chisel] def ref: Arg = if (isLit) litArg.get else lref + private[core] 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[core] 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..a2df2910 --- /dev/null +++ b/chiselFrontend/src/main/scala/chisel3/core/Mem.scala @@ -0,0 +1,134 @@ +// See LICENSE for license details. + +package chisel.core + +import scala.language.experimental.macros + +import chisel.internal._ +import chisel.internal.Builder.pushCommand +import chisel.internal.firrtl._ +import chisel.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..1de3efe5 --- /dev/null +++ b/chiselFrontend/src/main/scala/chisel3/core/Module.scala @@ -0,0 +1,119 @@ +// See LICENSE for license details. + +package chisel.core + +import scala.collection.mutable.{ArrayBuffer, HashSet} +import scala.language.experimental.macros + +import chisel.internal._ +import chisel.internal.Builder.pushCommand +import chisel.internal.Builder.dynamicContext +import chisel.internal.firrtl._ +import chisel.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[core] val _namespace = Builder.globalNamespace.child + private[chisel] val _commands = ArrayBuffer[Command]() + private[core] 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[core] def ports: Seq[(String,Data)] = Vector( + ("clk", clock), ("reset", reset), ("io", io) + ) + + private[core] 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[core] 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[core] 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/Printf.scala b/chiselFrontend/src/main/scala/chisel3/core/Printf.scala new file mode 100644 index 00000000..a7970816 --- /dev/null +++ b/chiselFrontend/src/main/scala/chisel3/core/Printf.scala @@ -0,0 +1,36 @@ +// See LICENSE for license details. + +package chisel.core + +import scala.language.experimental.macros + +import chisel.internal._ +import chisel.internal.Builder.pushCommand +import chisel.internal.firrtl._ +import chisel.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[core] 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..78461334 --- /dev/null +++ b/chiselFrontend/src/main/scala/chisel3/core/Reg.scala @@ -0,0 +1,71 @@ +// See LICENSE for license details. + +package chisel.core + +import chisel.internal._ +import chisel.internal.Builder.pushCommand +import chisel.internal.firrtl._ +import chisel.internal.sourceinfo.{SourceInfo, UnlocatableSourceInfo} + +object Reg { + private[core] 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..e31119a5 --- /dev/null +++ b/chiselFrontend/src/main/scala/chisel3/core/SeqUtils.scala @@ -0,0 +1,59 @@ +// See LICENSE for license details. + +package chisel.core + +import scala.language.experimental.macros + +import chisel.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..5d484313 --- /dev/null +++ b/chiselFrontend/src/main/scala/chisel3/core/When.scala @@ -0,0 +1,59 @@ +// See LICENSE for license details. + +package chisel.core + +import scala.language.experimental.macros + +import chisel.internal._ +import chisel.internal.Builder.pushCommand +import chisel.internal.firrtl._ +import chisel.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..01628105 --- /dev/null +++ b/chiselFrontend/src/main/scala/chisel3/internal/Builder.scala @@ -0,0 +1,129 @@ +// See LICENSE for license details. + +package chisel.internal + +import scala.util.DynamicVariable +import scala.collection.mutable.{ArrayBuffer, HashMap} + +import chisel._ +import core._ +import firrtl._ + +private[chisel] class Namespace(parent: Option[Namespace], keywords: Set[String]) { + private val names = collection.mutable.HashMap[String, Long]() + for (keyword <- keywords) + names(keyword) = 1 + + private def rename(n: String): String = { + val index = names.getOrElse(n, 1L) + val tryName = s"${n}_${index}" + names(n) = index + 1 + if (this contains tryName) rename(n) else tryName + } + + def contains(elem: String): Boolean = { + names.contains(elem) || parent.map(_ contains elem).getOrElse(false) + } + + def name(elem: String): String = { + if (this contains elem) { + name(rename(elem)) + } else { + names(elem) = 1 + 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..f0481dc4 --- /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.core._ + +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..c20bd130 --- /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..70e9938b --- /dev/null +++ b/chiselFrontend/src/main/scala/chisel3/internal/firrtl/IR.scala @@ -0,0 +1,190 @@ +// See LICENSE for license details. + +package chisel.internal.firrtl + +import chisel._ +import core._ +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]) -- cgit v1.2.3 From 3026dd214f3db3308eaf8f876d0fc03f75c577d3 Mon Sep 17 00:00:00 2001 From: Jim Lawson Date: Mon, 20 Jun 2016 11:38:26 -0700 Subject: Rename "package", "import", and explicit references to "chisel3". --- .../src/main/scala/chisel3/core/Aggregate.scala | 20 ++++++------- .../src/main/scala/chisel3/core/Assert.scala | 10 +++---- .../src/main/scala/chisel3/core/Bits.scala | 26 ++++++++--------- .../src/main/scala/chisel3/core/BlackBox.scala | 8 ++--- .../src/main/scala/chisel3/core/Data.scala | 20 ++++++------- .../src/main/scala/chisel3/core/Mem.scala | 10 +++---- .../src/main/scala/chisel3/core/Module.scala | 16 +++++----- .../src/main/scala/chisel3/core/Printf.scala | 10 +++---- .../src/main/scala/chisel3/core/Reg.scala | 10 +++---- .../src/main/scala/chisel3/core/SeqUtils.scala | 6 ++-- .../src/main/scala/chisel3/core/When.scala | 10 +++---- .../src/main/scala/chisel3/internal/Builder.scala | 34 +++++++++++----------- .../src/main/scala/chisel3/internal/Error.scala | 8 ++--- .../main/scala/chisel3/internal/SourceInfo.scala | 4 +-- .../main/scala/chisel3/internal/firrtl/IR.scala | 12 ++++---- 15 files changed, 102 insertions(+), 102 deletions(-) (limited to 'chiselFrontend/src') diff --git a/chiselFrontend/src/main/scala/chisel3/core/Aggregate.scala b/chiselFrontend/src/main/scala/chisel3/core/Aggregate.scala index 38a42fea..f2774a8d 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/Aggregate.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/Aggregate.scala @@ -1,15 +1,15 @@ // See LICENSE for license details. -package chisel.core +package chisel3.core import scala.collection.immutable.ListMap import scala.collection.mutable.{ArrayBuffer, HashSet, LinkedHashMap} import scala.language.experimental.macros -import chisel.internal._ -import chisel.internal.Builder.pushCommand -import chisel.internal.firrtl._ -import chisel.internal.sourceinfo.{SourceInfo, DeprecatedSourceInfo, VecTransform, SourceInfoTransform} +import chisel3.internal._ +import chisel3.internal.Builder.pushCommand +import chisel3.internal.firrtl._ +import chisel3.internal.sourceinfo.{SourceInfo, DeprecatedSourceInfo, VecTransform, SourceInfoTransform} /** An abstract class for data types that solely consist of (are an aggregate * of) other Data objects. @@ -163,8 +163,8 @@ sealed class Vec[T <: Data] private (gen: => T, val length: Int) 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] = + private[chisel3] def toType: String = s"${t.toType}[$length]" + private[chisel3] lazy val flatten: IndexedSeq[Bits] = (0 until length).flatMap(i => this.apply(i).flatten) for ((elt, i) <- self zipWithIndex) @@ -331,17 +331,17 @@ class Bundle extends Aggregate(NO_DIR) { } ArrayBuffer(nameMap.toSeq:_*) sortWith {case ((an, a), (bn, b)) => (a._id > b._id) || ((a eq b) && (an > bn))} } - private[chisel] def toType = { + private[chisel3] 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[chisel3] lazy val flatten = namedElts.flatMap(_._2.flatten) private[core] def addElt(name: String, elt: Data): Unit = namedElts += name -> elt - private[chisel] override def _onModuleClose: Unit = // scalastyle:ignore method.name + private[chisel3] override def _onModuleClose: Unit = // scalastyle:ignore method.name for ((name, elt) <- namedElts) { elt.setRef(this, _namespace.name(name)) } override def cloneType : this.type = { diff --git a/chiselFrontend/src/main/scala/chisel3/core/Assert.scala b/chiselFrontend/src/main/scala/chisel3/core/Assert.scala index 00cb00f4..c4727148 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/Assert.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/Assert.scala @@ -1,14 +1,14 @@ // See LICENSE for license details. -package chisel.core +package chisel3.core import scala.reflect.macros.blackbox.Context import scala.language.experimental.macros -import chisel.internal._ -import chisel.internal.Builder.pushCommand -import chisel.internal.firrtl._ -import chisel.internal.sourceinfo.SourceInfo +import chisel3.internal._ +import chisel3.internal.Builder.pushCommand +import chisel3.internal.firrtl._ +import chisel3.internal.sourceinfo.SourceInfo object assert { // scalastyle:ignore object.name /** Checks for a condition to be valid in the circuit at all times. If the diff --git a/chiselFrontend/src/main/scala/chisel3/core/Bits.scala b/chiselFrontend/src/main/scala/chisel3/core/Bits.scala index 38e71f8d..94d808a4 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/Bits.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/Bits.scala @@ -1,15 +1,15 @@ // See LICENSE for license details. -package chisel.core +package chisel3.core import scala.language.experimental.macros -import chisel.internal._ -import chisel.internal.Builder.pushOp -import chisel.internal.firrtl._ -import chisel.internal.sourceinfo.{SourceInfo, DeprecatedSourceInfo, SourceInfoTransform, SourceInfoWhiteboxTransform, +import chisel3.internal._ +import chisel3.internal.Builder.pushOp +import chisel3.internal.firrtl._ +import chisel3.internal.sourceinfo.{SourceInfo, DeprecatedSourceInfo, SourceInfoTransform, SourceInfoWhiteboxTransform, UIntTransform, MuxTransform} -import chisel.internal.firrtl.PrimOp._ +import chisel3.internal.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. @@ -25,9 +25,9 @@ sealed abstract class Bits(dirArg: Direction, width: Width, override val litArg: // 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[chisel3] def fromInt(x: BigInt, w: Int): this.type - private[chisel] def flatten: IndexedSeq[Bits] = IndexedSeq(this) + private[chisel3] def flatten: IndexedSeq[Bits] = IndexedSeq(this) def cloneType: this.type = cloneTypeWidth(width) @@ -360,9 +360,9 @@ sealed class UInt private[core] (dir: Direction, width: Width, lit: Option[ULit] extends Bits(dir, width, lit) with Num[UInt] { private[core] override def cloneTypeWidth(w: Width): this.type = new UInt(dir, w).asInstanceOf[this.type] - private[chisel] def toType = s"UInt$width" + private[chisel3] def toType = s"UInt$width" - override private[chisel] def fromInt(value: BigInt, width: Int): this.type = + override private[chisel3] def fromInt(value: BigInt, width: Int): this.type = UInt(value, width).asInstanceOf[this.type] override def := (that: Data)(implicit sourceInfo: SourceInfo): Unit = that match { @@ -537,14 +537,14 @@ sealed class SInt private (dir: Direction, width: Width, lit: Option[SLit] = Non extends Bits(dir, width, lit) with Num[SInt] { private[core] override def cloneTypeWidth(w: Width): this.type = new SInt(dir, w).asInstanceOf[this.type] - private[chisel] def toType = s"SInt$width" + private[chisel3] 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 = + override private[chisel3] def fromInt(value: BigInt, width: Int): this.type = SInt(value, width).asInstanceOf[this.type] final def unary_- (): SInt = macro SourceInfoTransform.noArg @@ -671,7 +671,7 @@ sealed class Bool(dir: Direction, lit: Option[ULit] = None) extends UInt(dir, Wi new Bool(dir).asInstanceOf[this.type] } - override private[chisel] def fromInt(value: BigInt, width: Int): this.type = { + override private[chisel3] def fromInt(value: BigInt, width: Int): this.type = { require((value == 0 || value == 1) && width == 1) Bool(value == 1).asInstanceOf[this.type] } diff --git a/chiselFrontend/src/main/scala/chisel3/core/BlackBox.scala b/chiselFrontend/src/main/scala/chisel3/core/BlackBox.scala index 2126ebce..eee8d598 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/BlackBox.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/BlackBox.scala @@ -1,10 +1,10 @@ // See LICENSE for license details. -package chisel.core +package chisel3.core -import chisel.internal.Builder.pushCommand -import chisel.internal.firrtl.{ModuleIO, DefInvalid} -import chisel.internal.sourceinfo.SourceInfo +import chisel3.internal.Builder.pushCommand +import chisel3.internal.firrtl.{ModuleIO, DefInvalid} +import chisel3.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 diff --git a/chiselFrontend/src/main/scala/chisel3/core/Data.scala b/chiselFrontend/src/main/scala/chisel3/core/Data.scala index cae38144..d5704369 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/Data.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/Data.scala @@ -1,13 +1,13 @@ // See LICENSE for license details. -package chisel.core +package chisel3.core import scala.language.experimental.macros -import chisel.internal._ -import chisel.internal.Builder.pushCommand -import chisel.internal.firrtl._ -import chisel.internal.sourceinfo.{SourceInfo, DeprecatedSourceInfo, UnlocatableSourceInfo, WireTransform, SourceInfoTransform} +import chisel3.internal._ +import chisel3.internal.Builder.pushCommand +import chisel3.internal.firrtl._ +import chisel3.internal.sourceinfo.{SourceInfo, DeprecatedSourceInfo, UnlocatableSourceInfo, WireTransform, SourceInfoTransform} sealed abstract class Direction(name: String) { override def toString: String = name @@ -53,9 +53,9 @@ abstract class Data(dirArg: Direction) extends HasId { private[core] def bulkConnect(that: Data)(implicit sourceInfo: SourceInfo): Unit = pushCommand(BulkConnect(sourceInfo, this.lref, that.lref)) private[core] def lref: Node = Node(this) - private[chisel] def ref: Arg = if (isLit) litArg.get else lref + private[chisel3] def ref: Arg = if (isLit) litArg.get else lref private[core] def cloneTypeWidth(width: Width): this.type - private[chisel] def toType: String + private[chisel3] def toType: String def := (that: Data)(implicit sourceInfo: SourceInfo): Unit = this badConnect that @@ -78,7 +78,7 @@ abstract class Data(dirArg: Direction) extends HasId { // 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] + private[chisel3] def flatten: IndexedSeq[Bits] /** Creates an new instance of this type, unpacking the input Bits into * structured data. @@ -145,9 +145,9 @@ object Clock { // 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[chisel3] override def flatten: IndexedSeq[Bits] = IndexedSeq() private[core] def cloneTypeWidth(width: Width): this.type = cloneType - private[chisel] def toType = "Clock" + private[chisel3] def toType = "Clock" override def := (that: Data)(implicit sourceInfo: SourceInfo): Unit = that match { case _: Clock => this connect that diff --git a/chiselFrontend/src/main/scala/chisel3/core/Mem.scala b/chiselFrontend/src/main/scala/chisel3/core/Mem.scala index a2df2910..38f5ef14 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/Mem.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/Mem.scala @@ -1,13 +1,13 @@ // See LICENSE for license details. -package chisel.core +package chisel3.core import scala.language.experimental.macros -import chisel.internal._ -import chisel.internal.Builder.pushCommand -import chisel.internal.firrtl._ -import chisel.internal.sourceinfo.{SourceInfo, DeprecatedSourceInfo, UnlocatableSourceInfo, MemTransform} +import chisel3.internal._ +import chisel3.internal.Builder.pushCommand +import chisel3.internal.firrtl._ +import chisel3.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") diff --git a/chiselFrontend/src/main/scala/chisel3/core/Module.scala b/chiselFrontend/src/main/scala/chisel3/core/Module.scala index 1de3efe5..7032e762 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/Module.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/Module.scala @@ -1,15 +1,15 @@ // See LICENSE for license details. -package chisel.core +package chisel3.core import scala.collection.mutable.{ArrayBuffer, HashSet} import scala.language.experimental.macros -import chisel.internal._ -import chisel.internal.Builder.pushCommand -import chisel.internal.Builder.dynamicContext -import chisel.internal.firrtl._ -import chisel.internal.sourceinfo.{SourceInfo, InstTransform, UnlocatableSourceInfo} +import chisel3.internal._ +import chisel3.internal.Builder.pushCommand +import chisel3.internal.Builder.dynamicContext +import chisel3.internal.firrtl._ +import chisel3.internal.sourceinfo.{SourceInfo, InstTransform, UnlocatableSourceInfo} object Module { /** A wrapper method that all Module instantiations must be wrapped in @@ -53,7 +53,7 @@ extends HasId { def this(_clock: Clock, _reset: Bool) = this(Option(_clock), Option(_reset)) private[core] val _namespace = Builder.globalNamespace.child - private[chisel] val _commands = ArrayBuffer[Command]() + private[chisel3] val _commands = ArrayBuffer[Command]() private[core] val _ids = ArrayBuffer[HasId]() dynamicContext.currentModule = Some(this) @@ -67,7 +67,7 @@ extends HasId { val clock = Clock(INPUT) val reset = Bool(INPUT) - private[chisel] def addId(d: HasId) { _ids += d } + private[chisel3] def addId(d: HasId) { _ids += d } private[core] def ports: Seq[(String,Data)] = Vector( ("clk", clock), ("reset", reset), ("io", io) diff --git a/chiselFrontend/src/main/scala/chisel3/core/Printf.scala b/chiselFrontend/src/main/scala/chisel3/core/Printf.scala index a7970816..b0a3c955 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/Printf.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/Printf.scala @@ -1,13 +1,13 @@ // See LICENSE for license details. -package chisel.core +package chisel3.core import scala.language.experimental.macros -import chisel.internal._ -import chisel.internal.Builder.pushCommand -import chisel.internal.firrtl._ -import chisel.internal.sourceinfo.SourceInfo +import chisel3.internal._ +import chisel3.internal.Builder.pushCommand +import chisel3.internal.firrtl._ +import chisel3.internal.sourceinfo.SourceInfo object printf { // scalastyle:ignore object.name /** Prints a message in simulation. diff --git a/chiselFrontend/src/main/scala/chisel3/core/Reg.scala b/chiselFrontend/src/main/scala/chisel3/core/Reg.scala index 78461334..b0dd3bb1 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/Reg.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/Reg.scala @@ -1,11 +1,11 @@ // See LICENSE for license details. -package chisel.core +package chisel3.core -import chisel.internal._ -import chisel.internal.Builder.pushCommand -import chisel.internal.firrtl._ -import chisel.internal.sourceinfo.{SourceInfo, UnlocatableSourceInfo} +import chisel3.internal._ +import chisel3.internal.Builder.pushCommand +import chisel3.internal.firrtl._ +import chisel3.internal.sourceinfo.{SourceInfo, UnlocatableSourceInfo} object Reg { private[core] def makeType[T <: Data](t: T = null, next: T = null, init: T = null): T = { diff --git a/chiselFrontend/src/main/scala/chisel3/core/SeqUtils.scala b/chiselFrontend/src/main/scala/chisel3/core/SeqUtils.scala index e31119a5..91cb9e89 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/SeqUtils.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/SeqUtils.scala @@ -1,12 +1,12 @@ // See LICENSE for license details. -package chisel.core +package chisel3.core import scala.language.experimental.macros -import chisel.internal.sourceinfo.{SourceInfo, SourceInfoTransform} +import chisel3.internal.sourceinfo.{SourceInfo, SourceInfoTransform} -private[chisel] object SeqUtils { +private[chisel3] object SeqUtils { /** Equivalent to Cat(r(n-1), ..., r(0)) */ def asUInt[T <: Bits](in: Seq[T]): UInt = macro SourceInfoTransform.inArg diff --git a/chiselFrontend/src/main/scala/chisel3/core/When.scala b/chiselFrontend/src/main/scala/chisel3/core/When.scala index 5d484313..196e7903 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/When.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/When.scala @@ -1,13 +1,13 @@ // See LICENSE for license details. -package chisel.core +package chisel3.core import scala.language.experimental.macros -import chisel.internal._ -import chisel.internal.Builder.pushCommand -import chisel.internal.firrtl._ -import chisel.internal.sourceinfo.{SourceInfo} +import chisel3.internal._ +import chisel3.internal.Builder.pushCommand +import chisel3.internal.firrtl._ +import chisel3.internal.sourceinfo.{SourceInfo} object when { // scalastyle:ignore object.name /** Create a `when` condition block, where whether a block of logic is diff --git a/chiselFrontend/src/main/scala/chisel3/internal/Builder.scala b/chiselFrontend/src/main/scala/chisel3/internal/Builder.scala index 01628105..0e0a88cc 100644 --- a/chiselFrontend/src/main/scala/chisel3/internal/Builder.scala +++ b/chiselFrontend/src/main/scala/chisel3/internal/Builder.scala @@ -1,15 +1,15 @@ // See LICENSE for license details. -package chisel.internal +package chisel3.internal import scala.util.DynamicVariable import scala.collection.mutable.{ArrayBuffer, HashMap} -import chisel._ +import chisel3._ import core._ import firrtl._ -private[chisel] class Namespace(parent: Option[Namespace], keywords: Set[String]) { +private[chisel3] class Namespace(parent: Option[Namespace], keywords: Set[String]) { private val names = collection.mutable.HashMap[String, Long]() for (keyword <- keywords) names(keyword) = 1 @@ -38,7 +38,7 @@ private[chisel] class Namespace(parent: Option[Namespace], keywords: Set[String] def child: Namespace = child(Set()) } -private[chisel] class IdGen { +private[chisel3] class IdGen { private var counter = -1L def next: Long = { counter += 1 @@ -46,12 +46,12 @@ private[chisel] class IdGen { } } -private[chisel] trait HasId { - private[chisel] def _onModuleClose {} // scalastyle:ignore method.name - private[chisel] val _parent = Builder.dynamicContext.currentModule +private[chisel3] trait HasId { + private[chisel3] def _onModuleClose {} // scalastyle:ignore method.name + private[chisel3] val _parent = Builder.dynamicContext.currentModule _parent.foreach(_.addId(this)) - private[chisel] val _id = Builder.idGen.next + private[chisel3] 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 @@ -68,12 +68,12 @@ private[chisel] trait HasId { for(hook <- postname_hooks) { hook(name) } this } - private[chisel] def addPostnameHook(hook: String=>Unit): Unit = postname_hooks += hook + private[chisel3] 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 = + private[chisel3] def forceName(default: =>String, namespace: Namespace): Unit = if(_ref.isEmpty) { val candidate_name = suggested_name.getOrElse(default) val available_name = namespace.name(candidate_name) @@ -81,14 +81,14 @@ private[chisel] trait HasId { } 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[chisel3] def setRef(imm: Arg): Unit = _ref = Some(imm) + private[chisel3] def setRef(parent: HasId, name: String): Unit = setRef(Slot(Node(parent), name)) + private[chisel3] def setRef(parent: HasId, index: Int): Unit = setRef(Index(Node(parent), ILit(index))) + private[chisel3] def setRef(parent: HasId, index: UInt): Unit = setRef(Index(Node(parent), index.ref)) + private[chisel3] def getRef: Arg = _ref.get } -private[chisel] class DynamicContext { +private[chisel3] class DynamicContext { val idGen = new IdGen val globalNamespace = new Namespace(None, Set()) val components = ArrayBuffer[Component]() @@ -96,7 +96,7 @@ private[chisel] class DynamicContext { val errors = new ErrorLog } -private[chisel] object Builder { +private[chisel3] object Builder { // All global mutable state must be referenced via dynamicContextVar!! private val dynamicContextVar = new DynamicVariable[Option[DynamicContext]](None) diff --git a/chiselFrontend/src/main/scala/chisel3/internal/Error.scala b/chiselFrontend/src/main/scala/chisel3/internal/Error.scala index f0481dc4..7ae0580f 100644 --- a/chiselFrontend/src/main/scala/chisel3/internal/Error.scala +++ b/chiselFrontend/src/main/scala/chisel3/internal/Error.scala @@ -1,20 +1,20 @@ // See LICENSE for license details. -package chisel.internal +package chisel3.internal import scala.collection.mutable.ArrayBuffer -import chisel.core._ +import chisel3.core._ class ChiselException(message: String, cause: Throwable) extends Exception(message, cause) -private[chisel] object throwException { +private[chisel3] 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 { +private[chisel3] class ErrorLog { def hasErrors: Boolean = errors.exists(_.isFatal) /** Log an error message */ diff --git a/chiselFrontend/src/main/scala/chisel3/internal/SourceInfo.scala b/chiselFrontend/src/main/scala/chisel3/internal/SourceInfo.scala index c20bd130..5e3bf33e 100644 --- a/chiselFrontend/src/main/scala/chisel3/internal/SourceInfo.scala +++ b/chiselFrontend/src/main/scala/chisel3/internal/SourceInfo.scala @@ -12,7 +12,7 @@ // writers to append source locator information at the point of a library // function invocation. -package chisel.internal.sourceinfo +package chisel3.internal.sourceinfo import scala.language.experimental.macros import scala.reflect.macros.blackbox.Context @@ -42,7 +42,7 @@ 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})" + q"_root_.chisel3.internal.sourceinfo.SourceLine(${p.source.file.name}, ${p.line}, ${p.column})" } } diff --git a/chiselFrontend/src/main/scala/chisel3/internal/firrtl/IR.scala b/chiselFrontend/src/main/scala/chisel3/internal/firrtl/IR.scala index 70e9938b..64d7d5fd 100644 --- a/chiselFrontend/src/main/scala/chisel3/internal/firrtl/IR.scala +++ b/chiselFrontend/src/main/scala/chisel3/internal/firrtl/IR.scala @@ -1,11 +1,11 @@ // See LICENSE for license details. -package chisel.internal.firrtl +package chisel3.internal.firrtl -import chisel._ +import chisel3._ import core._ -import chisel.internal._ -import chisel.internal.sourceinfo.{SourceInfo, NoSourceInfo} +import chisel3.internal._ +import chisel3.internal.sourceinfo.{SourceInfo, NoSourceInfo} case class PrimOp(val name: String) { override def toString: String = name @@ -55,8 +55,8 @@ case class Node(id: HasId) extends Arg { } 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) + private[chisel3] def forcedWidth = widthArg.known + private[chisel3] def width: Width = if (forcedWidth) widthArg else Width(minWidth) protected def minWidth: Int if (forcedWidth) { -- cgit v1.2.3 From 70a41e5aed5dc3bc52133aecf46049a5946d33fe Mon Sep 17 00:00:00 2001 From: Howard Mao Date: Mon, 20 Jun 2016 16:00:19 -0700 Subject: fix BlackBox setRefs to correctly handle arbitrarily nested bundles as ports (#223) --- chiselFrontend/src/main/scala/chisel/core/BlackBox.scala | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) (limited to 'chiselFrontend/src') diff --git a/chiselFrontend/src/main/scala/chisel/core/BlackBox.scala b/chiselFrontend/src/main/scala/chisel/core/BlackBox.scala index 2126ebce..0e4c7a0c 100644 --- a/chiselFrontend/src/main/scala/chisel/core/BlackBox.scala +++ b/chiselFrontend/src/main/scala/chisel/core/BlackBox.scala @@ -28,13 +28,21 @@ abstract class BlackBox extends Module { // Do not do reflective naming of internal signals, just name io override private[core] 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 + for ((name, port) <- ports) { + port.setRef(ModuleIO(this, _namespace.name(name))) + } + // We need to call forceName and onModuleClose on all of the sub-elements + // of the io bundle, but NOT on the io bundle itself. + // Doing so would cause the wrong names to be assigned, since their parent + // is now the module itself instead of the io bundle. + for (id <- _ids; if id ne io) { + id.forceName(default="T", _namespace) + id._onModuleClose + } this } -- cgit v1.2.3 From d675043717593fb7e96fb0f1952debbeb7f20a57 Mon Sep 17 00:00:00 2001 From: Jim Lawson Date: Tue, 21 Jun 2016 09:17:30 -0700 Subject: New Module, IO, Input/Output wrapping. --- chiselFrontend/src/main/scala/Chisel/Assert.scala | 4 +- chiselFrontend/src/main/scala/Chisel/Module.scala | 66 +++++++++++++++++----- .../src/main/scala/Chisel/internal/Builder.scala | 26 +++++++-- 3 files changed, 75 insertions(+), 21 deletions(-) (limited to 'chiselFrontend/src') diff --git a/chiselFrontend/src/main/scala/Chisel/Assert.scala b/chiselFrontend/src/main/scala/Chisel/Assert.scala index c086f014..4187c579 100644 --- a/chiselFrontend/src/main/scala/Chisel/Assert.scala +++ b/chiselFrontend/src/main/scala/Chisel/Assert.scala @@ -50,12 +50,12 @@ object assert { // scalastyle:ignore object.name } def apply_impl_do(cond: Bool, line: String, message: Option[String])(implicit sourceInfo: SourceInfo) { - when (!(cond || Builder.dynamicContext.currentModule.get.reset)) { + when (!(cond || Builder.forcedModule.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)) + pushCommand(Stop(sourceInfo, Node(Builder.forcedModule.clock), 1)) } } diff --git a/chiselFrontend/src/main/scala/Chisel/Module.scala b/chiselFrontend/src/main/scala/Chisel/Module.scala index e2101538..4fba6b25 100644 --- a/chiselFrontend/src/main/scala/Chisel/Module.scala +++ b/chiselFrontend/src/main/scala/Chisel/Module.scala @@ -8,8 +8,9 @@ import scala.language.experimental.macros import internal._ import internal.Builder.pushCommand import internal.Builder.dynamicContext -import internal.firrtl._ import internal.sourceinfo.{SourceInfo, InstTransform, UnlocatableSourceInfo} +import internal.firrtl +import internal.firrtl.{Command, Component, DefInstance, DefInvalid, ModuleIO} object Module { /** A wrapper method that all Module instantiations must be wrapped in @@ -26,14 +27,19 @@ object Module { // module de-duplication in FIRRTL emission. val childSourceInfo = UnlocatableSourceInfo - val parent = dynamicContext.currentModule - val m = bc.setRefs() + val parent: Option[Module] = Builder.currentModule + val m = bc.setRefs() // This will set currentModule! m._commands.prepend(DefInvalid(childSourceInfo, m.io.ref)) // init module outputs - dynamicContext.currentModule = parent + Builder.currentModule = parent // Back to parent! val ports = m.computePorts Builder.components += Component(m, m.name, ports, m._commands) - pushCommand(DefInstance(sourceInfo, m, ports)) - m.setupInParent(childSourceInfo) + // Avoid referencing 'parent' in top module + if(!Builder.currentModule.isEmpty) { + pushCommand(DefInstance(sourceInfo, m, ports)) + m.setupInParent(childSourceInfo) + } + + m } } @@ -52,10 +58,41 @@ extends HasId { def this(_reset: Bool) = this(None, Option(_reset)) def this(_clock: Clock, _reset: Bool) = this(Option(_clock), Option(_reset)) + // This function binds the iodef as a port in the hardware graph + private[Chisel] def Port[T<:Data](iodef: T): iodef.type = { + // Bind each element of the iodef to being a Port + Binding.bind(iodef, PortBinder(this), "Error: iodef") + iodef + } + + private[this] var ioDefined: Boolean = false + + /** + * This must wrap the datatype used to set the io field of any Module. + * i.e. All concrete modules must have defined io in this form: + * [lazy] val io[: io type] = IO(...[: io type]) + * + * Items in [] are optional. + * + * The granted iodef WILL NOT be cloned (to allow for more seamless use of + * anonymous Bundles in the IO) and thus CANNOT have been bound to any logic. + * This will error if any node is bound (e.g. due to logic in a Bundle + * constructor, which is considered improper). + * + * TODO(twigg): Specifically walk the Data definition to call out which nodes + * are problematic. + */ + def IO[T<:Data](iodef: T): iodef.type = { + require(!ioDefined, "Another IO definition for this module was already declared!") + ioDefined = true + + Port(iodef) + } + private[Chisel] val _namespace = Builder.globalNamespace.child private[Chisel] val _commands = ArrayBuffer[Command]() private[Chisel] val _ids = ArrayBuffer[HasId]() - dynamicContext.currentModule = Some(this) + Builder.currentModule = Some(this) /** Name of the instance. */ val name = Builder.globalNamespace.name(getClass.getName.split('.').last) @@ -64,8 +101,8 @@ extends HasId { * connections in and out of a Module may only go through `io` elements. */ def io: Bundle - val clock = Clock(INPUT) - val reset = Bool(INPUT) + val clock = Port(Input(Clock())) + val reset = Port(Input(Bool())) private[Chisel] def addId(d: HasId) { _ids += d } @@ -73,10 +110,13 @@ extends HasId { ("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 computePorts: Seq[firrtl.Port] = + for((name, port) <- ports) yield { + // Port definitions need to know input or output at top-level. + // By FIRRTL semantics, 'flipped' becomes an Input + val direction = if(Data.isFlipped(port)) Direction.Input else Direction.Output + firrtl.Port(port, direction) + } private[Chisel] def setupInParent(implicit sourceInfo: SourceInfo): this.type = { _parent match { diff --git a/chiselFrontend/src/main/scala/Chisel/internal/Builder.scala b/chiselFrontend/src/main/scala/Chisel/internal/Builder.scala index d0e28b7c..fddc4bd7 100644 --- a/chiselFrontend/src/main/scala/Chisel/internal/Builder.scala +++ b/chiselFrontend/src/main/scala/Chisel/internal/Builder.scala @@ -41,11 +41,11 @@ private[Chisel] class IdGen { } private[Chisel] trait HasId { - private[Chisel] def _onModuleClose {} // scalastyle:ignore method.name - private[Chisel] val _parent = Builder.dynamicContext.currentModule + private[Chisel] def _onModuleClose: Unit = {} // scalastyle:ignore method.name + private[Chisel] val _parent: Option[Module] = Builder.currentModule _parent.foreach(_.addId(this)) - private[Chisel] val _id = Builder.idGen.next + private[Chisel] val _id: Long = Builder.idGen.next override def hashCode: Int = _id.toInt override def equals(that: Any): Boolean = that match { case x: HasId => _id == x._id @@ -93,15 +93,29 @@ private[Chisel] class DynamicContext { private[Chisel] object Builder { // All global mutable state must be referenced via dynamicContextVar!! private val dynamicContextVar = new DynamicVariable[Option[DynamicContext]](None) + private def dynamicContext: DynamicContext = + dynamicContextVar.value.getOrElse(new DynamicContext) - 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 currentModule: Option[Module] = dynamicContext.currentModule + def currentModule_=(target: Option[Module]): Unit = { + dynamicContext.currentModule = target + } + def forcedModule: Module = currentModule match { + case Some(module) => module + case None => throw new Exception( + "Error: Not in a Module. Likely cause: Missed Module() wrap or bare chisel API call." + // A bare api call is, e.g. calling Wire() from the scala console). + ) + } + + // TODO(twigg): Ideally, binding checks and new bindings would all occur here + // However, rest of frontend can't support this yet. def pushCommand[T <: Command](c: T): T = { - dynamicContext.currentModule.foreach(_._commands += c) + forcedModule._commands += c c } def pushOp[T <: Data](cmd: DefPrim[T]): T = pushCommand(cmd).id -- cgit v1.2.3 From 083610b2faa456dfccc4365dd115565d36e522fa Mon Sep 17 00:00:00 2001 From: Jim Lawson Date: Tue, 21 Jun 2016 10:13:51 -0700 Subject: Most of the remaining tests with Module, IO wrapping. --- chiselFrontend/src/main/scala/Chisel/Printf.scala | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'chiselFrontend/src') diff --git a/chiselFrontend/src/main/scala/Chisel/Printf.scala b/chiselFrontend/src/main/scala/Chisel/Printf.scala index f068f637..cc121eac 100644 --- a/chiselFrontend/src/main/scala/Chisel/Printf.scala +++ b/chiselFrontend/src/main/scala/Chisel/Printf.scala @@ -24,13 +24,13 @@ object printf { // scalastyle:ignore object.name * @param data format string varargs containing data to print */ def apply(fmt: String, data: Bits*)(implicit sourceInfo: SourceInfo) { - when (!(Builder.dynamicContext.currentModule.get.reset)) { + when (!Builder.forcedModule.reset) { printfWithoutReset(fmt, data:_*) } } private[Chisel] def printfWithoutReset(fmt: String, data: Bits*)(implicit sourceInfo: SourceInfo) { - val clock = Builder.dynamicContext.currentModule.get.clock + val clock = Builder.forcedModule.clock pushCommand(Printf(sourceInfo, Node(clock), fmt, data.map((d: Bits) => d.ref))) } } -- cgit v1.2.3 From 2e9b41cafe9158f20ecb03ae9eabecb82e557829 Mon Sep 17 00:00:00 2001 From: Andrew Waterman Date: Thu, 23 Jun 2016 12:14:34 -0700 Subject: Expose FIRRTL stop construct --- chiselFrontend/src/main/scala/chisel/core/Assert.scala | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'chiselFrontend/src') diff --git a/chiselFrontend/src/main/scala/chisel/core/Assert.scala b/chiselFrontend/src/main/scala/chisel/core/Assert.scala index 00cb00f4..f665843b 100644 --- a/chiselFrontend/src/main/scala/chisel/core/Assert.scala +++ b/chiselFrontend/src/main/scala/chisel/core/Assert.scala @@ -71,3 +71,17 @@ object assert { // scalastyle:ignore object.name Predef.assert(cond, "") } } + +object stop { // scalastyle:ignore object.name + /** Terminate execution with a failure code. */ + def apply(code: Int)(implicit sourceInfo: SourceInfo): Unit = { + when (!Builder.dynamicContext.currentModule.get.reset) { + pushCommand(Stop(sourceInfo, Node(Builder.dynamicContext.currentModule.get.clock), code)) + } + } + + /** Terminate execution, indicating success. */ + def apply()(implicit sourceInfo: SourceInfo): Unit = { + stop(0) + } +} -- cgit v1.2.3 From 378edecbf797f19cf26f5a4d6a3ed3df701ba66d Mon Sep 17 00:00:00 2001 From: Andrew Waterman Date: Fri, 1 Jul 2016 11:54:49 -0700 Subject: Reflectively name Module fields declared in superclasses Closes #229 h/t @sdtwigg @davidbiancolin --- chiselFrontend/src/main/scala/chisel3/core/Module.scala | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'chiselFrontend/src') diff --git a/chiselFrontend/src/main/scala/chisel3/core/Module.scala b/chiselFrontend/src/main/scala/chisel3/core/Module.scala index 7032e762..cde7032d 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/Module.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/Module.scala @@ -2,7 +2,7 @@ package chisel3.core -import scala.collection.mutable.{ArrayBuffer, HashSet} +import scala.collection.mutable.ArrayBuffer import scala.language.experimental.macros import chisel3.internal._ @@ -96,7 +96,11 @@ extends HasId { } // Suggest names to nodes using runtime reflection - val valNames = HashSet[String](getClass.getDeclaredFields.map(_.getName):_*) + def getValNames(c: Class[_]): Set[String] = { + if (c == classOf[Module]) Set() + else getValNames(c.getSuperclass) ++ c.getDeclaredFields.map(_.getName) + } + val valNames = getValNames(this.getClass) def isPublicVal(m: java.lang.reflect.Method) = m.getParameterTypes.isEmpty && valNames.contains(m.getName) val methods = getClass.getMethods.sortWith(_.getName > _.getName) -- cgit v1.2.3 From 8fc61aeab7c50a5bf2ff6f6f8ab46e960cce2adf Mon Sep 17 00:00:00 2001 From: Andrew Waterman Date: Fri, 15 Jul 2016 00:09:05 -0700 Subject: Improve PopCount implementation Clean up Scala code, and use +& to generate a lot less FIRRTL --- chiselFrontend/src/main/scala/chisel3/core/SeqUtils.scala | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) (limited to 'chiselFrontend/src') diff --git a/chiselFrontend/src/main/scala/chisel3/core/SeqUtils.scala b/chiselFrontend/src/main/scala/chisel3/core/SeqUtils.scala index 91cb9e89..0872ec41 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/SeqUtils.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/SeqUtils.scala @@ -23,14 +23,10 @@ private[chisel3] object SeqUtils { /** 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))) - } + def do_count(in: Seq[Bool])(implicit sourceInfo: SourceInfo): UInt = in.size match { + case 0 => UInt(0) + case 1 => in.head + case n => count(in take n/2) +& count(in drop n/2) } /** Returns data value corresponding to first true predicate */ -- cgit v1.2.3 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 +++++ 34 files changed, 2958 insertions(+), 2353 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 (limited to 'chiselFrontend/src') 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]) -- cgit v1.2.3 From 12810b5efe6a8f872fbc1c63cdfb835ca354624f Mon Sep 17 00:00:00 2001 From: Jim Lawson Date: Wed, 6 Jul 2016 09:31:47 -0700 Subject: Update Chisel -> chisel3 references. --- .../src/main/scala/chisel3/core/Aggregate.scala | 30 ++++++------ .../src/main/scala/chisel3/core/Assert.scala | 24 ++++++++-- .../src/main/scala/chisel3/core/BiConnect.scala | 8 ++-- .../src/main/scala/chisel3/core/Binder.scala | 2 +- .../src/main/scala/chisel3/core/Binding.scala | 2 +- .../src/main/scala/chisel3/core/Bits.scala | 46 +++++++++--------- .../src/main/scala/chisel3/core/BlackBox.scala | 28 +++++++---- .../src/main/scala/chisel3/core/Data.scala | 38 +++++++-------- .../src/main/scala/chisel3/core/Mem.scala | 10 ++-- .../src/main/scala/chisel3/core/Module.scala | 29 ++++++------ .../src/main/scala/chisel3/core/MonoConnect.scala | 8 ++-- .../src/main/scala/chisel3/core/Printf.scala | 12 ++--- .../src/main/scala/chisel3/core/Reg.scala | 13 +++--- .../src/main/scala/chisel3/core/SeqUtils.scala | 6 +-- .../src/main/scala/chisel3/core/When.scala | 10 ++-- .../src/main/scala/chisel3/internal/Builder.scala | 54 ++++++++++++---------- .../src/main/scala/chisel3/internal/Error.scala | 8 ++-- .../main/scala/chisel3/internal/SourceInfo.scala | 4 +- .../main/scala/chisel3/internal/firrtl/IR.scala | 14 +++--- 19 files changed, 189 insertions(+), 157 deletions(-) (limited to 'chiselFrontend/src') diff --git a/chiselFrontend/src/main/scala/chisel3/core/Aggregate.scala b/chiselFrontend/src/main/scala/chisel3/core/Aggregate.scala index 1eef5d69..a453d5e0 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/Aggregate.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/Aggregate.scala @@ -1,21 +1,21 @@ // See LICENSE for license details. -package Chisel +package chisel3.core 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} +import chisel3.internal._ +import chisel3.internal.Builder.pushCommand +import chisel3.internal.firrtl._ +import chisel3.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 + private[core] def cloneTypeWidth(width: Width): this.type = cloneType def width: Width = flatten.map(_.width).reduce(_ + _) } @@ -163,8 +163,8 @@ sealed class Vec[T <: Data] private (gen: => T, val length: Int) 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] = + private[chisel3] def toType: String = s"${t.toType}[$length]" + private[chisel3] lazy val flatten: IndexedSeq[Bits] = (0 until length).flatMap(i => this.apply(i).flatten) for ((elt, i) <- self zipWithIndex) @@ -315,7 +315,7 @@ class Bundle extends Aggregate(NO_DIR) { /** Returns a list of elements in this Bundle. */ - private[Chisel] lazy val namedElts = { + private[core] lazy val namedElts = { val nameMap = LinkedHashMap[String, Data]() val seen = HashSet[Data]() for (m <- getClass.getMethods.sortWith(_.getName < _.getName)) { @@ -331,17 +331,17 @@ class Bundle extends Aggregate(NO_DIR) { } ArrayBuffer(nameMap.toSeq:_*) sortWith {case ((an, a), (bn, b)) => (a._id > b._id) || ((a eq b) && (an > bn))} } - private[Chisel] def toType = { + private[chisel3] 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 = + private[chisel3] lazy val flatten = namedElts.flatMap(_._2.flatten) + private[core] def addElt(name: String, elt: Data): Unit = namedElts += name -> elt - private[Chisel] override def _onModuleClose: Unit = // scalastyle:ignore method.name + private[chisel3] override def _onModuleClose: Unit = // scalastyle:ignore method.name for ((name, elt) <- namedElts) { elt.setRef(this, _namespace.name(name)) } override def cloneType : this.type = { @@ -372,6 +372,6 @@ class Bundle extends Aggregate(NO_DIR) { } } -private[Chisel] object Bundle { - val keywords = List("flip", "asInput", "asOutput", "cloneType", "toBits") +private[core] object Bundle { + val keywords = List("flip", "asInput", "asOutput", "cloneType", "toBits", "newType") } diff --git a/chiselFrontend/src/main/scala/chisel3/core/Assert.scala b/chiselFrontend/src/main/scala/chisel3/core/Assert.scala index c086f014..9e792a51 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/Assert.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/Assert.scala @@ -1,14 +1,14 @@ // See LICENSE for license details. -package Chisel +package chisel3.core import scala.reflect.macros.blackbox.Context import scala.language.experimental.macros -import internal._ -import internal.Builder.pushCommand -import internal.firrtl._ -import internal.sourceinfo.SourceInfo +import chisel3.internal._ +import chisel3.internal.Builder.pushCommand +import chisel3.internal.firrtl._ +import chisel3.internal.sourceinfo.SourceInfo object assert { // scalastyle:ignore object.name /** Checks for a condition to be valid in the circuit at all times. If the @@ -71,3 +71,17 @@ object assert { // scalastyle:ignore object.name Predef.assert(cond, "") } } + +object stop { // scalastyle:ignore object.name + /** Terminate execution with a failure code. */ + def apply(code: Int)(implicit sourceInfo: SourceInfo): Unit = { + when (!Builder.forcedModule.reset) { + pushCommand(Stop(sourceInfo, Node(Builder.forcedModule.clock), code)) + } + } + + /** Terminate execution, indicating success. */ + def apply()(implicit sourceInfo: SourceInfo): Unit = { + stop(0) + } +} diff --git a/chiselFrontend/src/main/scala/chisel3/core/BiConnect.scala b/chiselFrontend/src/main/scala/chisel3/core/BiConnect.scala index 42d85bfb..cb76159a 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/BiConnect.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/BiConnect.scala @@ -1,9 +1,9 @@ -package Chisel +package chisel3.core -import internal.Builder.pushCommand -import internal.firrtl.Connect +import chisel3.internal.Builder.pushCommand +import chisel3.internal.firrtl.Connect import scala.language.experimental.macros -import internal.sourceinfo.{SourceInfo, DeprecatedSourceInfo, UnlocatableSourceInfo, WireTransform, SourceInfoTransform} +import chisel3.internal.sourceinfo.{SourceInfo, DeprecatedSourceInfo, UnlocatableSourceInfo, WireTransform, SourceInfoTransform} /** * BiConnect.connect executes a bidirectional connection element-wise. diff --git a/chiselFrontend/src/main/scala/chisel3/core/Binder.scala b/chiselFrontend/src/main/scala/chisel3/core/Binder.scala index ca074527..c7346dce 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/Binder.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/Binder.scala @@ -1,4 +1,4 @@ -package Chisel +package chisel3.core /** * A Binder is a function from UnboundBinding to some Binding. diff --git a/chiselFrontend/src/main/scala/chisel3/core/Binding.scala b/chiselFrontend/src/main/scala/chisel3/core/Binding.scala index 949ac9cd..d8d9ebd2 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/Binding.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/Binding.scala @@ -1,4 +1,4 @@ -package Chisel +package chisel3.core /** * The purpose of a Binding is to indicate what type of hardware 'entity' a diff --git a/chiselFrontend/src/main/scala/chisel3/core/Bits.scala b/chiselFrontend/src/main/scala/chisel3/core/Bits.scala index bc8cc8e2..e6a4be71 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/Bits.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/Bits.scala @@ -1,15 +1,15 @@ // See LICENSE for license details. -package Chisel +package chisel3.core import scala.language.experimental.macros -import internal._ -import internal.Builder.pushOp -import internal.firrtl._ -import internal.sourceinfo.{SourceInfo, DeprecatedSourceInfo, SourceInfoTransform, SourceInfoWhiteboxTransform, +import chisel3.internal._ +import chisel3.internal.Builder.pushOp +import chisel3.internal.firrtl._ +import chisel3.internal.sourceinfo.{SourceInfo, DeprecatedSourceInfo, SourceInfoTransform, SourceInfoWhiteboxTransform, UIntTransform, MuxTransform} -import firrtl.PrimOp._ +import chisel3.internal.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. @@ -25,9 +25,9 @@ sealed abstract class Bits(dirArg: Direction, width: Width, override val litArg: // 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[chisel3] def fromInt(x: BigInt, w: Int): this.type - private[Chisel] def flatten: IndexedSeq[Bits] = IndexedSeq(this) + private[chisel3] def flatten: IndexedSeq[Bits] = IndexedSeq(this) def cloneType: this.type = cloneTypeWidth(width) @@ -118,16 +118,16 @@ sealed abstract class Bits(dirArg: Direction, width: Width, override val litArg: 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 = + private[core] 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 = + private[core] 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 = + private[core] 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 = + private[core] 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 = + private[core] def redop(sourceInfo: SourceInfo, op: PrimOp): Bool = pushOp(DefPrim(sourceInfo, Bool(), op, this.ref)) /** Returns this wire zero padded up to the specified width. @@ -356,13 +356,13 @@ abstract trait Num[T <: Data] { /** 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) +sealed class UInt private[core] (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 = + private[core] override def cloneTypeWidth(w: Width): this.type = new UInt(dir, w).asInstanceOf[this.type] - private[Chisel] def toType = s"UInt$width" + private[core] def toType = s"UInt$width" - override private[Chisel] def fromInt(value: BigInt, width: Int): this.type = + override private[chisel3] def fromInt(value: BigInt, width: Int): this.type = UInt(value, width).asInstanceOf[this.type] override def := (that: Data)(implicit sourceInfo: SourceInfo): Unit = that match { @@ -482,7 +482,7 @@ sealed class UInt private[Chisel] (dir: Direction, width: Width, lit: Option[ULi } // This is currently a factory because both Bits and UInt inherit it. -private[Chisel] sealed trait UIntFactory { +private[core] 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. */ @@ -535,16 +535,16 @@ 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 = + private[core] override def cloneTypeWidth(w: Width): this.type = new SInt(dir, w).asInstanceOf[this.type] - private[Chisel] def toType = s"SInt$width" + private[chisel3] 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 = + override private[chisel3] def fromInt(value: BigInt, width: Int): this.type = SInt(value, width).asInstanceOf[this.type] final def unary_- (): SInt = macro SourceInfoTransform.noArg @@ -666,12 +666,12 @@ object SInt { /** 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 = { + private[core] 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 = { + override private[chisel3] def fromInt(value: BigInt, width: Int): this.type = { require((value == 0 || value == 1) && width == 1) Bool(value == 1).asInstanceOf[this.type] } diff --git a/chiselFrontend/src/main/scala/chisel3/core/BlackBox.scala b/chiselFrontend/src/main/scala/chisel3/core/BlackBox.scala index b634f021..f2d9558d 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/BlackBox.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/BlackBox.scala @@ -1,10 +1,10 @@ // See LICENSE for license details. -package Chisel +package chisel3.core -import internal.Builder.pushCommand -import internal.firrtl.{ModuleIO, DefInvalid} -import internal.sourceinfo.SourceInfo +import chisel3.internal.Builder.pushCommand +import chisel3.internal.firrtl.{ModuleIO, DefInvalid} +import chisel3.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 @@ -24,23 +24,31 @@ abstract class BlackBox extends Module { // 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 + override private[core] 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))) - } + override private[core] def setRefs(): this.type = { // 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 + for ((name, port) <- ports) { + port.setRef(ModuleIO(this, _namespace.name(name))) + } + // We need to call forceName and onModuleClose on all of the sub-elements + // of the io bundle, but NOT on the io bundle itself. + // Doing so would cause the wrong names to be assigned, since their parent + // is now the module itself instead of the io bundle. + for (id <- _ids; if id ne io) { + id.forceName(default="T", _namespace) + id._onModuleClose + } 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 { + override private[core] def setupInParent(implicit sourceInfo: SourceInfo): this.type = _parent match { case Some(p) => { // Just init instance inputs for((_,port) <- ports) pushCommand(DefInvalid(sourceInfo, port.ref)) diff --git a/chiselFrontend/src/main/scala/chisel3/core/Data.scala b/chiselFrontend/src/main/scala/chisel3/core/Data.scala index d16843f7..fcdc86bb 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/Data.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/Data.scala @@ -1,13 +1,13 @@ // See LICENSE for license details. -package Chisel +package chisel3.core import scala.language.experimental.macros -import internal._ -import internal.Builder.pushCommand -import internal.firrtl._ -import internal.sourceinfo.{SourceInfo, DeprecatedSourceInfo, UnlocatableSourceInfo, WireTransform, SourceInfoTransform} +import chisel3.internal._ +import chisel3.internal.Builder.pushCommand +import chisel3.internal.firrtl._ +import chisel3.internal.sourceinfo.{SourceInfo, DeprecatedSourceInfo, UnlocatableSourceInfo, WireTransform, SourceInfoTransform} sealed abstract class Direction(name: String) { override def toString: String = name @@ -38,9 +38,9 @@ abstract class Data(dirArg: Direction) extends HasId { // 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[core] def isFlip = isFlipVar - private[Chisel] def overrideDirection(newDir: Direction => Direction, + private[core] def overrideDirection(newDir: Direction => Direction, newFlip: Boolean => Boolean): this.type = { this.isFlipVar = newFlip(this.isFlipVar) for (field <- this.flatten) @@ -51,16 +51,16 @@ abstract class Data(dirArg: Direction) extends HasId { 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 = + private[core] 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 = + private[core] 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 = + private[core] 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 + private[core] def lref: Node = Node(this) + private[chisel3] def ref: Arg = if (isLit) litArg.get else lref + private[core] def cloneTypeWidth(width: Width): this.type + private[chisel3] def toType: String def := (that: Data)(implicit sourceInfo: SourceInfo): Unit = this badConnect that @@ -71,7 +71,7 @@ abstract class Data(dirArg: Direction) extends HasId { def litValue(): BigInt = litArg.get.num def isLit(): Boolean = litArg.isDefined - def width: Width + private[core] def width: Width final def getWidth: Int = width.get // While this being in the Data API doesn't really make sense (should be in @@ -83,7 +83,7 @@ abstract class Data(dirArg: Direction) extends HasId { // 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] + private[chisel3] def flatten: IndexedSeq[Bits] /** Creates an new instance of this type, unpacking the input Bits into * structured data. @@ -150,9 +150,9 @@ object Clock { // 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" + private[chisel3] override def flatten: IndexedSeq[Bits] = IndexedSeq() + private[core] def cloneTypeWidth(width: Width): this.type = cloneType + private[chisel3] def toType = "Clock" override def := (that: Data)(implicit sourceInfo: SourceInfo): Unit = that match { case _: Clock => this connect that diff --git a/chiselFrontend/src/main/scala/chisel3/core/Mem.scala b/chiselFrontend/src/main/scala/chisel3/core/Mem.scala index e34d5499..38f5ef14 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/Mem.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/Mem.scala @@ -1,13 +1,13 @@ // See LICENSE for license details. -package Chisel +package chisel3.core import scala.language.experimental.macros -import internal._ -import internal.Builder.pushCommand -import internal.firrtl._ -import internal.sourceinfo.{SourceInfo, DeprecatedSourceInfo, UnlocatableSourceInfo, MemTransform} +import chisel3.internal._ +import chisel3.internal.Builder.pushCommand +import chisel3.internal.firrtl._ +import chisel3.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") diff --git a/chiselFrontend/src/main/scala/chisel3/core/Module.scala b/chiselFrontend/src/main/scala/chisel3/core/Module.scala index e2101538..5d510112 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/Module.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/Module.scala @@ -1,15 +1,16 @@ // See LICENSE for license details. -package Chisel +package chisel3.core 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} +import chisel3.internal._ +import chisel3.internal.Builder.pushCommand +import chisel3.internal.Builder.dynamicContext +import chisel3.internal.firrtl._ +import chisel3.internal.firrtl.{Command, Component, DefInstance, DefInvalid, ModuleIO} +import chisel3.internal.sourceinfo.{SourceInfo, InstTransform, UnlocatableSourceInfo} object Module { /** A wrapper method that all Module instantiations must be wrapped in @@ -52,9 +53,9 @@ extends HasId { 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]() + private[core] val _namespace = Builder.globalNamespace.child + private[chisel3] val _commands = ArrayBuffer[Command]() + private[core] val _ids = ArrayBuffer[HasId]() dynamicContext.currentModule = Some(this) /** Name of the instance. */ @@ -67,18 +68,18 @@ extends HasId { val clock = Clock(INPUT) val reset = Bool(INPUT) - private[Chisel] def addId(d: HasId) { _ids += d } + private[chisel3] def addId(d: HasId) { _ids += d } - private[Chisel] def ports: Seq[(String,Data)] = Vector( + private[core] def ports: Seq[(String,Data)] = Vector( ("clk", clock), ("reset", reset), ("io", io) ) - private[Chisel] def computePorts = for((name, port) <- ports) yield { + private[core] 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 = { + private[core] def setupInParent(implicit sourceInfo: SourceInfo): this.type = { _parent match { case Some(p) => { pushCommand(DefInvalid(sourceInfo, io.ref)) // init instance inputs @@ -90,7 +91,7 @@ extends HasId { } } - private[Chisel] def setRefs(): this.type = { + private[core] def setRefs(): this.type = { for ((name, port) <- ports) { port.setRef(ModuleIO(this, _namespace.name(name))) } diff --git a/chiselFrontend/src/main/scala/chisel3/core/MonoConnect.scala b/chiselFrontend/src/main/scala/chisel3/core/MonoConnect.scala index 27da965b..64c71cb2 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/MonoConnect.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/MonoConnect.scala @@ -1,9 +1,9 @@ -package Chisel +package chisel3.core -import internal.Builder.pushCommand -import internal.firrtl.Connect +import chisel3.internal.Builder.pushCommand +import chisel3.internal.firrtl.Connect import scala.language.experimental.macros -import internal.sourceinfo.{SourceInfo, DeprecatedSourceInfo, UnlocatableSourceInfo, WireTransform, SourceInfoTransform} +import chisel3.internal.sourceinfo.{SourceInfo, DeprecatedSourceInfo, UnlocatableSourceInfo, WireTransform, SourceInfoTransform} /** * MonoConnect.connect executes a mono-directional connection element-wise. diff --git a/chiselFrontend/src/main/scala/chisel3/core/Printf.scala b/chiselFrontend/src/main/scala/chisel3/core/Printf.scala index f068f637..b0a3c955 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/Printf.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/Printf.scala @@ -1,13 +1,13 @@ // See LICENSE for license details. -package Chisel +package chisel3.core import scala.language.experimental.macros -import internal._ -import internal.Builder.pushCommand -import internal.firrtl._ -import internal.sourceinfo.SourceInfo +import chisel3.internal._ +import chisel3.internal.Builder.pushCommand +import chisel3.internal.firrtl._ +import chisel3.internal.sourceinfo.SourceInfo object printf { // scalastyle:ignore object.name /** Prints a message in simulation. @@ -29,7 +29,7 @@ object printf { // scalastyle:ignore object.name } } - private[Chisel] def printfWithoutReset(fmt: String, data: Bits*)(implicit sourceInfo: SourceInfo) { + private[core] 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 index c8faa5c9..14ae9650 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/Reg.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/Reg.scala @@ -1,14 +1,15 @@ // See LICENSE for license details. -package Chisel +package chisel3.core -import internal._ -import internal.Builder.pushCommand -import internal.firrtl._ -import internal.sourceinfo.{SourceInfo, UnlocatableSourceInfo} +import chisel3.internal._ +import chisel3.internal.Builder.pushCommand +import chisel3.internal.firrtl._ +import chisel3.internal.sourceinfo.{SourceInfo, UnlocatableSourceInfo} object Reg { - private[Chisel] def makeType[T <: Data](t: T = null, next: T = null, init: T = null): T = { + private[core] 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) { diff --git a/chiselFrontend/src/main/scala/chisel3/core/SeqUtils.scala b/chiselFrontend/src/main/scala/chisel3/core/SeqUtils.scala index 9a15fd5f..91cb9e89 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/SeqUtils.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/SeqUtils.scala @@ -1,12 +1,12 @@ // See LICENSE for license details. -package Chisel +package chisel3.core import scala.language.experimental.macros -import internal.sourceinfo.{SourceInfo, SourceInfoTransform} +import chisel3.internal.sourceinfo.{SourceInfo, SourceInfoTransform} -private[Chisel] object SeqUtils { +private[chisel3] object SeqUtils { /** Equivalent to Cat(r(n-1), ..., r(0)) */ def asUInt[T <: Bits](in: Seq[T]): UInt = macro SourceInfoTransform.inArg diff --git a/chiselFrontend/src/main/scala/chisel3/core/When.scala b/chiselFrontend/src/main/scala/chisel3/core/When.scala index 90b3d1a5..196e7903 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/When.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/When.scala @@ -1,13 +1,13 @@ // See LICENSE for license details. -package Chisel +package chisel3.core import scala.language.experimental.macros -import internal._ -import internal.Builder.pushCommand -import internal.firrtl._ -import internal.sourceinfo.{SourceInfo} +import chisel3.internal._ +import chisel3.internal.Builder.pushCommand +import chisel3.internal.firrtl._ +import chisel3.internal.sourceinfo.{SourceInfo} object when { // scalastyle:ignore object.name /** Create a `when` condition block, where whether a block of logic is diff --git a/chiselFrontend/src/main/scala/chisel3/internal/Builder.scala b/chiselFrontend/src/main/scala/chisel3/internal/Builder.scala index d0e28b7c..0e0a88cc 100644 --- a/chiselFrontend/src/main/scala/chisel3/internal/Builder.scala +++ b/chiselFrontend/src/main/scala/chisel3/internal/Builder.scala @@ -1,29 +1,35 @@ // See LICENSE for license details. -package Chisel.internal +package chisel3.internal import scala.util.DynamicVariable import scala.collection.mutable.{ArrayBuffer, HashMap} -import Chisel._ -import Chisel.internal.firrtl._ +import chisel3._ +import core._ +import firrtl._ -private[Chisel] class Namespace(parent: Option[Namespace], keywords: Set[String]) { - private var i = 0L - private val names = collection.mutable.HashSet[String]() +private[chisel3] class Namespace(parent: Option[Namespace], keywords: Set[String]) { + private val names = collection.mutable.HashMap[String, Long]() + for (keyword <- keywords) + names(keyword) = 1 - private def rename(n: String) = { i += 1; s"${n}_${i}" } + private def rename(n: String): String = { + val index = names.getOrElse(n, 1L) + val tryName = s"${n}_${index}" + names(n) = index + 1 + if (this contains tryName) rename(n) else tryName + } def contains(elem: String): Boolean = { - keywords.contains(elem) || names.contains(elem) || - parent.map(_ contains elem).getOrElse(false) + names.contains(elem) || parent.map(_ contains elem).getOrElse(false) } def name(elem: String): String = { if (this contains elem) { name(rename(elem)) } else { - names += elem + names(elem) = 1 elem } } @@ -32,7 +38,7 @@ private[Chisel] class Namespace(parent: Option[Namespace], keywords: Set[String] def child: Namespace = child(Set()) } -private[Chisel] class IdGen { +private[chisel3] class IdGen { private var counter = -1L def next: Long = { counter += 1 @@ -40,12 +46,12 @@ private[Chisel] class IdGen { } } -private[Chisel] trait HasId { - private[Chisel] def _onModuleClose {} // scalastyle:ignore method.name - private[Chisel] val _parent = Builder.dynamicContext.currentModule +private[chisel3] trait HasId { + private[chisel3] def _onModuleClose {} // scalastyle:ignore method.name + private[chisel3] val _parent = Builder.dynamicContext.currentModule _parent.foreach(_.addId(this)) - private[Chisel] val _id = Builder.idGen.next + private[chisel3] 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 @@ -62,12 +68,12 @@ private[Chisel] trait HasId { for(hook <- postname_hooks) { hook(name) } this } - private[Chisel] def addPostnameHook(hook: String=>Unit): Unit = postname_hooks += hook + private[chisel3] 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 = + private[chisel3] def forceName(default: =>String, namespace: Namespace): Unit = if(_ref.isEmpty) { val candidate_name = suggested_name.getOrElse(default) val available_name = namespace.name(candidate_name) @@ -75,14 +81,14 @@ private[Chisel] trait HasId { } 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[chisel3] def setRef(imm: Arg): Unit = _ref = Some(imm) + private[chisel3] def setRef(parent: HasId, name: String): Unit = setRef(Slot(Node(parent), name)) + private[chisel3] def setRef(parent: HasId, index: Int): Unit = setRef(Index(Node(parent), ILit(index))) + private[chisel3] def setRef(parent: HasId, index: UInt): Unit = setRef(Index(Node(parent), index.ref)) + private[chisel3] def getRef: Arg = _ref.get } -private[Chisel] class DynamicContext { +private[chisel3] class DynamicContext { val idGen = new IdGen val globalNamespace = new Namespace(None, Set()) val components = ArrayBuffer[Component]() @@ -90,7 +96,7 @@ private[Chisel] class DynamicContext { val errors = new ErrorLog } -private[Chisel] object Builder { +private[chisel3] object Builder { // All global mutable state must be referenced via dynamicContextVar!! private val dynamicContextVar = new DynamicVariable[Option[DynamicContext]](None) diff --git a/chiselFrontend/src/main/scala/chisel3/internal/Error.scala b/chiselFrontend/src/main/scala/chisel3/internal/Error.scala index 6c4c0880..7ae0580f 100644 --- a/chiselFrontend/src/main/scala/chisel3/internal/Error.scala +++ b/chiselFrontend/src/main/scala/chisel3/internal/Error.scala @@ -1,20 +1,20 @@ // See LICENSE for license details. -package Chisel.internal +package chisel3.internal import scala.collection.mutable.ArrayBuffer -import Chisel._ +import chisel3.core._ class ChiselException(message: String, cause: Throwable) extends Exception(message, cause) -private[Chisel] object throwException { +private[chisel3] 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 { +private[chisel3] class ErrorLog { def hasErrors: Boolean = errors.exists(_.isFatal) /** Log an error message */ diff --git a/chiselFrontend/src/main/scala/chisel3/internal/SourceInfo.scala b/chiselFrontend/src/main/scala/chisel3/internal/SourceInfo.scala index 66bfc7a4..5e3bf33e 100644 --- a/chiselFrontend/src/main/scala/chisel3/internal/SourceInfo.scala +++ b/chiselFrontend/src/main/scala/chisel3/internal/SourceInfo.scala @@ -12,7 +12,7 @@ // writers to append source locator information at the point of a library // function invocation. -package Chisel.internal.sourceinfo +package chisel3.internal.sourceinfo import scala.language.experimental.macros import scala.reflect.macros.blackbox.Context @@ -42,7 +42,7 @@ 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})" + q"_root_.chisel3.internal.sourceinfo.SourceLine(${p.source.file.name}, ${p.line}, ${p.column})" } } diff --git a/chiselFrontend/src/main/scala/chisel3/internal/firrtl/IR.scala b/chiselFrontend/src/main/scala/chisel3/internal/firrtl/IR.scala index 62784cee..64d7d5fd 100644 --- a/chiselFrontend/src/main/scala/chisel3/internal/firrtl/IR.scala +++ b/chiselFrontend/src/main/scala/chisel3/internal/firrtl/IR.scala @@ -1,9 +1,11 @@ // See LICENSE for license details. -package Chisel.internal.firrtl -import Chisel._ -import Chisel.internal._ -import Chisel.internal.sourceinfo.{SourceInfo, NoSourceInfo} +package chisel3.internal.firrtl + +import chisel3._ +import core._ +import chisel3.internal._ +import chisel3.internal.sourceinfo.{SourceInfo, NoSourceInfo} case class PrimOp(val name: String) { override def toString: String = name @@ -53,8 +55,8 @@ case class Node(id: HasId) extends Arg { } 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) + private[chisel3] def forcedWidth = widthArg.known + private[chisel3] def width: Width = if (forcedWidth) widthArg else Width(minWidth) protected def minWidth: Int if (forcedWidth) { -- cgit v1.2.3 From 3120eefc8a73b5ab3d8f909445a3e004b5e60cc6 Mon Sep 17 00:00:00 2001 From: Jim Lawson Date: Tue, 19 Jul 2016 15:08:22 -0700 Subject: Incorporate connection logic. Compiles but fails tests. --- .../src/main/scala/chisel3/core/Aggregate.scala | 70 ++++++---- .../src/main/scala/chisel3/core/Bits.scala | 149 ++++++++++++--------- .../src/main/scala/chisel3/core/Data.scala | 143 ++++++++++++++------ .../src/main/scala/chisel3/core/Module.scala | 2 +- 4 files changed, 233 insertions(+), 131 deletions(-) (limited to 'chiselFrontend/src') diff --git a/chiselFrontend/src/main/scala/chisel3/core/Aggregate.scala b/chiselFrontend/src/main/scala/chisel3/core/Aggregate.scala index a453d5e0..1b49e163 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/Aggregate.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/Aggregate.scala @@ -14,9 +14,9 @@ import chisel3.internal.sourceinfo.{SourceInfo, DeprecatedSourceInfo, VecTransfo /** 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[core] def cloneTypeWidth(width: Width): this.type = cloneType - def width: Width = flatten.map(_.width).reduce(_ + _) +sealed abstract class Aggregate extends Data { + private[chisel3] def cloneTypeWidth(width: Width): this.type = cloneType + private[chisel3] def width: Width = flatten.map(_.width).reduce(_ + _) } object Vec { @@ -105,28 +105,40 @@ object Vec { * 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] { + extends Aggregate 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 + /** + * sample_element 'tracks' all changes to the elements of self. + * For consistency, sample_element is always used for creating dynamically + * indexed ports and outputing the FIRRTL type. + * + * Needed specifically for the case when the Vec is length 0. + */ + private[core] val sample_element: T = gen + + // allElements current includes sample_element + // This is somewhat weird although I think the best course of action here is + // to deprecate allElements in favor of dispatched functions to Data or + // a pattern matched recursive descent + private[chisel3] final def allElements: Seq[Element] = + (sample_element +: self).flatMap(_.allElements) /** 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 + 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 := that.asInstanceOf[Data] - - override def := (that: Data)(implicit sourceInfo: SourceInfo): Unit = that match { - case _: Vec[_] => this connect that - case _ => this badConnect that - } + def <> (that: Vec[T])(implicit sourceInfo: SourceInfo): Unit = this bulkConnect that.asInstanceOf[Data] /** Strong bulk connect, assigning elements in this Vec from elements in a Seq. * @@ -144,9 +156,17 @@ sealed class Vec[T <: Data] private (gen: => T, val length: Int) /** Creates a dynamically indexed read or write accessor into the array. */ def apply(idx: UInt): T = { - val x = gen - x.setRef(this, idx) - x + Binding.checkSynthesizable(idx ,s"'idx' ($idx)") + val port = sample_element.cloneType + port.setRef(this, idx) //TODO(twigg): This is a bit too magical + + // Bind each element of port to being whatever the base type is + // Using the head element as the sample_element + for((port_elem, model_elem) <- port.allElements zip sample_element.allElements) { + port_elem.binding = model_elem.binding + } + + port } /** Creates a statically indexed read or write accessor into the array. @@ -162,8 +182,7 @@ sealed class Vec[T <: Data] private (gen: => T, val length: Int) override def cloneType: this.type = Vec(length, gen).asInstanceOf[this.type] - private val t = gen - private[chisel3] def toType: String = s"${t.toType}[$length]" + private[chisel3] def toType: String = s"${sample_element.toType}[$length]" private[chisel3] lazy val flatten: IndexedSeq[Bits] = (0 until length).flatMap(i => this.apply(i).flatten) @@ -256,7 +275,7 @@ trait VecLike[T <: Data] extends collection.IndexedSeq[T] with HasId { * 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) { +class Bundle extends Aggregate { private val _namespace = Builder.globalNamespace.child // TODO: replace with better defined FIRRTL weak-connect operator @@ -272,13 +291,6 @@ class Bundle extends Aggregate(NO_DIR) { * 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:_*) @@ -333,7 +345,7 @@ class Bundle extends Aggregate(NO_DIR) { } private[chisel3] def toType = { def eltPort(elt: Data): String = { - val flipStr = if (elt.isFlip) "flip " else "" + val flipStr: String = if(Data.isFlipped(elt)) "flip " else "" s"${flipStr}${elt.getRef.name} : ${elt.toType}" } s"{${namedElts.reverse.map(e => eltPort(e._2)).mkString(", ")}}" @@ -343,6 +355,8 @@ class Bundle extends Aggregate(NO_DIR) { namedElts += name -> elt private[chisel3] override def _onModuleClose: Unit = // scalastyle:ignore method.name for ((name, elt) <- namedElts) { elt.setRef(this, _namespace.name(name)) } + + private[chisel3] final def allElements: Seq[Element] = namedElts.flatMap(_._2.allElements) override def cloneType : this.type = { // If the user did not provide a cloneType method, try invoking one of @@ -373,5 +387,5 @@ class Bundle extends Aggregate(NO_DIR) { } private[core] object Bundle { - val keywords = List("flip", "asInput", "asOutput", "cloneType", "toBits", "newType") + val keywords = List("flip", "asInput", "asOutput", "cloneType", "toBits") } diff --git a/chiselFrontend/src/main/scala/chisel3/core/Bits.scala b/chiselFrontend/src/main/scala/chisel3/core/Bits.scala index e6a4be71..b18a43d9 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/Bits.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/Bits.scala @@ -14,13 +14,35 @@ import chisel3.internal.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) +abstract class Element(private[core] val width: Width) extends Data { + /** + * Elements can actually be bound to the hardware graph and thus must store + * that binding information. + */ + private[this] var _binding: Binding = UnboundBinding(None) + // Define setter/getter pairing + // Can only bind something that has not yet been bound. + private[core] def binding_=(target: Binding): Unit = _binding match { + case UnboundBinding(_) => { + _binding = target + _binding + } + case _ => throw Binding.AlreadyBoundException(_binding.toString) + // Other checks should have caught this. + } + private[core] def binding = _binding + + /** Return the binding for some bits. */ + def dir: Direction = binding.direction.get + + private[chisel3] final def allElements: Seq[Element] = Seq(this) +} /** 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) { +sealed abstract class Bits(width: Width, override val litArg: Option[LitArg]) + extends Element(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 @@ -31,8 +53,6 @@ sealed abstract class Bits(dirArg: Direction, width: Width, override val litArg: 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 @@ -52,7 +72,7 @@ sealed abstract class Bits(dirArg: Direction, width: Width, override val litArg: case KnownWidth(x) => require(x >= n, s"Can't head($n) for width $x < $n") case UnknownWidth() => } - binop(sourceInfo, UInt(width = n), HeadOp, n) + binop(sourceInfo, UInt(Width(n)), HeadOp, n) } /** Returns the specified bit on this wire as a [[Bool]], statically @@ -67,6 +87,7 @@ sealed abstract class Bits(dirArg: Direction, width: Width, override val litArg: if (isLit()) { Bool(((litValue() >> x.toInt) & 1) == 1) } else { + Binding.checkSynthesizable(this, s"'this' ($this)") pushOp(DefPrim(sourceInfo, Bool(), BitsExtractOp, this.ref, ILit(x), ILit(x))) } } @@ -108,7 +129,8 @@ sealed abstract class Bits(dirArg: Direction, width: Width, override val litArg: if (isLit()) { UInt((litValue >> y) & ((BigInt(1) << w) - 1), w) } else { - pushOp(DefPrim(sourceInfo, UInt(width = w), BitsExtractOp, this.ref, ILit(x), ILit(y))) + Binding.checkSynthesizable(this, s"'this' ($this)") + pushOp(DefPrim(sourceInfo, UInt(Width(w)), BitsExtractOp, this.ref, ILit(x), ILit(y))) } } @@ -118,17 +140,28 @@ sealed abstract class Bits(dirArg: Direction, width: Width, override val litArg: final def do_apply(x: BigInt, y: BigInt)(implicit sourceInfo: SourceInfo): UInt = apply(x.toInt, y.toInt) - private[core] def unop[T <: Data](sourceInfo: SourceInfo, dest: T, op: PrimOp): T = + private[core] def unop[T <: Data](sourceInfo: SourceInfo, dest: T, op: PrimOp): T = { + Binding.checkSynthesizable(this, s"'this' ($this)") pushOp(DefPrim(sourceInfo, dest, op, this.ref)) - private[core] def binop[T <: Data](sourceInfo: SourceInfo, dest: T, op: PrimOp, other: BigInt): T = + } + private[core] def binop[T <: Data](sourceInfo: SourceInfo, dest: T, op: PrimOp, other: BigInt): T = { + Binding.checkSynthesizable(this, s"'this' ($this)") pushOp(DefPrim(sourceInfo, dest, op, this.ref, ILit(other))) - private[core] def binop[T <: Data](sourceInfo: SourceInfo, dest: T, op: PrimOp, other: Bits): T = + } + private[core] def binop[T <: Data](sourceInfo: SourceInfo, dest: T, op: PrimOp, other: Bits): T = { + Binding.checkSynthesizable(this, s"'this' ($this)") + Binding.checkSynthesizable(other, s"'other' ($other)") pushOp(DefPrim(sourceInfo, dest, op, this.ref, other.ref)) - - private[core] def compop(sourceInfo: SourceInfo, op: PrimOp, other: Bits): Bool = + } + private[core] def compop(sourceInfo: SourceInfo, op: PrimOp, other: Bits): Bool = { + Binding.checkSynthesizable(this, s"'this' ($this)") + Binding.checkSynthesizable(other, s"'other' ($other)") pushOp(DefPrim(sourceInfo, Bool(), op, this.ref, other.ref)) - private[core] def redop(sourceInfo: SourceInfo, op: PrimOp): Bool = + } + private[core] def redop(sourceInfo: SourceInfo, op: PrimOp): Bool = { + Binding.checkSynthesizable(this, s"'this' ($this)") pushOp(DefPrim(sourceInfo, Bool(), op, this.ref)) + } /** Returns this wire zero padded up to the specified width. * @@ -356,19 +389,19 @@ abstract trait Num[T <: Data] { /** A data type for unsigned integers, represented as a binary bitvector. * Defines arithmetic operations between other integer types. */ -sealed class UInt private[core] (dir: Direction, width: Width, lit: Option[ULit] = None) - extends Bits(dir, width, lit) with Num[UInt] { - private[core] override def cloneTypeWidth(w: Width): this.type = - new UInt(dir, w).asInstanceOf[this.type] - private[core] def toType = s"UInt$width" +sealed class UInt private[core] (width: Width, lit: Option[ULit] = None) + extends Bits(width, lit) with Num[UInt] { - override private[chisel3] def fromInt(value: BigInt, width: Int): this.type = - UInt(value, width).asInstanceOf[this.type] + if (lit != None) { + this.binding = LitBinding() - override def := (that: Data)(implicit sourceInfo: SourceInfo): Unit = that match { - case _: UInt => this connect that - case _ => this badConnect that } + private[chisel3] override def cloneTypeWidth(w: Width): this.type = + new UInt(w).asInstanceOf[this.type] + private[chisel3] def toType = s"UInt$width" + + override private[chisel3] def fromInt(value: BigInt, width: Int): this.type = + UInt(value, width).asInstanceOf[this.type] // TODO: refactor to share documentation with Num or add independent scaladoc final def unary_- (): UInt = macro SourceInfoTransform.noArg @@ -442,7 +475,7 @@ sealed class UInt private[core] (dir: Direction, width: Width, lit: Option[ULit] final def unary_! () : Bool = macro SourceInfoTransform.noArg - def do_unary_! (implicit sourceInfo: SourceInfo) : Bool = this === Bits(0) + def do_unary_! (implicit sourceInfo: SourceInfo) : Bool = this === UInt(0, 1) override def do_<< (that: Int)(implicit sourceInfo: SourceInfo): UInt = binop(sourceInfo, UInt(this.width + that), ShiftLeftOp, that) @@ -484,12 +517,11 @@ sealed class UInt private[core] (dir: Direction, width: Width, lit: Option[ULit] // This is currently a factory because both Bits and UInt inherit it. private[core] 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()) - + def apply(): UInt = apply(Width()) + /** Create a UInt port with specified width. */ + def apply(width: Width): UInt = new UInt(width) + /** Create a UInt with a specified width - compatibility with Chisel2. */ + def apply(dummy: Option[Direction] = None, width: Int): UInt = apply(Width(width)) /** Create a UInt literal with inferred width. */ def apply(value: BigInt): UInt = apply(value, Width()) /** Create a UInt literal with fixed width. */ @@ -497,16 +529,13 @@ private[core] sealed trait UIntFactory { /** 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)) + val result = new UInt(lit.width, Some(lit)) + // Bind result to being an Literal +// result.binding = LitBinding() + result } private def parse(n: String) = { @@ -533,16 +562,12 @@ private[core] sealed trait UIntFactory { 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[core] override def cloneTypeWidth(w: Width): this.type = - new SInt(dir, w).asInstanceOf[this.type] - private[chisel3] def toType = s"SInt$width" +sealed class SInt private (width: Width, lit: Option[SLit] = None) + extends Bits(width, lit) with Num[SInt] { - override def := (that: Data)(implicit sourceInfo: SourceInfo): Unit = that match { - case _: SInt => this connect that - case _ => this badConnect that - } + private[chisel3] override def cloneTypeWidth(w: Width): this.type = + new SInt(w).asInstanceOf[this.type] + private[chisel3] def toType = s"SInt$width" override private[chisel3] def fromInt(value: BigInt, width: Int): this.type = SInt(value, width).asInstanceOf[this.type] @@ -639,25 +664,24 @@ sealed class SInt private (dir: Direction, width: Width, lit: Option[SLit] = Non 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()) + def apply(): SInt = apply(Width()) + /** Create a SInt type or port with fixed width. */ + def apply(width: Int): SInt = apply(Width(width)) + /** Create an SInt type with specified width. */ + def apply(width: Width): SInt = new SInt(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)) + val result = new SInt(lit.width, Some(lit)) + // Bind result to being an Literal + result.binding = LitBinding() + result } } @@ -665,10 +689,10 @@ object SInt { // 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[core] override def cloneTypeWidth(w: Width): this.type = { +sealed class Bool(lit: Option[ULit] = None) extends UInt(Width(1), lit) { + private[chisel3] override def cloneTypeWidth(w: Width): this.type = { require(!w.known || w.get == 1) - new Bool(dir).asInstanceOf[this.type] + new Bool().asInstanceOf[this.type] } override private[chisel3] def fromInt(value: BigInt, width: Int): this.type = { @@ -709,11 +733,11 @@ sealed class Bool(dir: Direction, lit: Option[ULit] = None) extends UInt(dir, Wi object Bool { /** Creates an empty Bool. */ - def apply(dir: Direction = NO_DIR): Bool = new Bool(dir) + def apply(): Bool = new Bool() /** Creates Bool literal. */ - def apply(x: Boolean): Bool = new Bool(NO_DIR, Some(ULit(if (x) 1 else 0, Width(1)))) + def apply(x: Boolean): Bool = new Bool(Some(ULit(if (x) 1 else 0, Width(1)))) } object Mux { @@ -742,6 +766,9 @@ object Mux { 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}") + Binding.checkSynthesizable(cond, s"'cond' ($cond)") + Binding.checkSynthesizable(con, s"'con' ($con)") + Binding.checkSynthesizable(alt, s"'alt' ($alt)") val d = alt.cloneTypeWidth(con.width max alt.width) pushOp(DefPrim(sourceInfo, d, MultiplexOp, cond.ref, con.ref, alt.ref)) } diff --git a/chiselFrontend/src/main/scala/chisel3/core/Data.scala b/chiselFrontend/src/main/scala/chisel3/core/Data.scala index fcdc86bb..4cc66cb5 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/Data.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/Data.scala @@ -13,18 +13,69 @@ 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 } +object Direction { + object Input extends Direction("input") { override def flip: Direction = Output } + object Output extends Direction("output") { override def flip: Direction = Input } +} @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, !_) +object DataMirror { + def widthOf(target: Data): Width = target.width +} + +/** +* Input, Output, and Flipped are used to define the directions of Module IOs. +* +* Note that they do not currently call target to be a newType or cloneType. +* This is nominally for performance reasons to avoid too many extra copies when +* something is flipped multiple times. +* +* Thus, an error will be thrown if these are used on bound Data +*/ +object Input { + def apply[T<:Data](target: T): T = + Binding.bind(target, InputBinder, "Error: Cannot set as input ") +} +object Output { + def apply[T<:Data](target: T): T = + Binding.bind(target, OutputBinder, "Error: Cannot set as output ") +} +object Flipped { + def apply[T<:Data](target: T): T = + Binding.bind(target, FlippedBinder, "Error: Cannot flip ") +} + +object Data { + /** + * This function returns true if the FIRRTL type of this Data should be flipped + * relative to other nodes. + * + * Note that the current scheme only applies Flip to Elements or Vec chains of + * Elements. + * + * A Bundle is never marked flip, instead preferring its root fields to be marked + * + * The Vec check is due to the fact that flip must be factored out of the vec, ie: + * must have flip field: Vec(UInt) instead of field: Vec(flip UInt) + */ + private[chisel3] def isFlipped(target: Data): Boolean = target match { + case (element: Element) => element.binding.direction == Some(Direction.Input) + case (vec: Vec[Data @unchecked]) => isFlipped(vec.sample_element) + case (bundle: Bundle) => false + } + + implicit class AddDirectionToData[T<:Data](val target: T) extends AnyVal { + @deprecated("Input(Data) should be used over Data.asInput", "gchisel") + def asInput: T = Input(target) + @deprecated("Output(Data) should be used over Data.asOutput", "gchisel") + def asOutput: T = Output(target) + @deprecated("Flipped(Data) should be used over Data.flip", "gchisel") + def flip(): T = Flipped(target) + } } /** This forms the root of the type system for wire data types. The data value @@ -32,41 +83,45 @@ trait Flipped extends Data { * 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[core] def isFlip = isFlipVar - - private[core] 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, !_) +abstract class Data extends HasId { + // Return ALL elements at root of this type. + // Contasts with flatten, which returns just Bits + private[chisel3] def allElements: Seq[Element] private[core] def badConnect(that: Data)(implicit sourceInfo: SourceInfo): Unit = throwException(s"cannot connect ${this} and ${that}") - private[core] def connect(that: Data)(implicit sourceInfo: SourceInfo): Unit = - pushCommand(Connect(sourceInfo, this.lref, that.ref)) - private[core] def bulkConnect(that: Data)(implicit sourceInfo: SourceInfo): Unit = - pushCommand(BulkConnect(sourceInfo, this.lref, that.lref)) - private[core] def lref: Node = Node(this) + private[chisel3] def connect(that: Data)(implicit sourceInfo: SourceInfo): Unit = { + Binding.checkSynthesizable(this, s"'this' ($this)") + Binding.checkSynthesizable(that, s"'that' ($that)") + try { + MonoConnect.connect(sourceInfo, this, that, Builder.forcedModule) + } catch { + case MonoConnect.MonoConnectException(message) => + throwException( + s"Connection between sink ($this) and source ($that) failed @$message" + ) + } + } + private[chisel3] def bulkConnect(that: Data)(implicit sourceInfo: SourceInfo): Unit = { + Binding.checkSynthesizable(this, s"'this' ($this)") + Binding.checkSynthesizable(that, s"'that' ($that)") + try { + BiConnect.connect(sourceInfo, this, that, Builder.forcedModule) + } catch { + case BiConnect.BiConnectException(message) => + throwException( + s"Connection between left ($this) and source ($that) failed @$message" + ) + } + } + private[chisel3] def lref: Node = Node(this) private[chisel3] def ref: Arg = if (isLit) litArg.get else lref - private[core] def cloneTypeWidth(width: Width): this.type + private[chisel3] def cloneTypeWidth(width: Width): this.type private[chisel3] 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 + final def := (that: Data)(implicit sourceInfo: SourceInfo): Unit = this connect that + final def <> (that: Data)(implicit sourceInfo: SourceInfo): Unit = this bulkConnect that def litArg(): Option[LitArg] = None def litValue(): BigInt = litArg.get.num def isLit(): Boolean = litArg.isDefined @@ -134,28 +189,34 @@ object Wire { def do_apply[T <: Data](t: T, init: T)(implicit sourceInfo: SourceInfo): T = { val x = Reg.makeType(t, null.asInstanceOf[T], init) + + // Bind each element of x to being a Wire + Binding.bind(x, WireBinder(Builder.forcedModule), "Error: t") + pushCommand(DefWire(sourceInfo, x)) pushCommand(DefInvalid(sourceInfo, x.ref)) if (init != null) { + Binding.checkSynthesizable(init, s"'init' ($init)") x := init } + x } } object Clock { - def apply(dir: Direction = NO_DIR): Clock = new Clock(dir) + def apply(): Clock = new Clock } // TODO: Document this. -sealed class Clock(dirArg: Direction) extends Element(dirArg, Width(1)) { - def cloneType: this.type = Clock(dirArg).asInstanceOf[this.type] +sealed class Clock extends Element(Width(1)) { + def cloneType: this.type = Clock().asInstanceOf[this.type] private[chisel3] override def flatten: IndexedSeq[Bits] = IndexedSeq() - private[core] def cloneTypeWidth(width: Width): this.type = cloneType + private[chisel3] def cloneTypeWidth(width: Width): this.type = cloneType private[chisel3] def toType = "Clock" - override def := (that: Data)(implicit sourceInfo: SourceInfo): Unit = that match { - case _: Clock => this connect that - case _ => this badConnect that + override def connect (that: Data)(implicit sourceInfo: SourceInfo): Unit = that match { + case _: Clock => super.connect(that)(sourceInfo) + case _ => super.badConnect(that)(sourceInfo) } } diff --git a/chiselFrontend/src/main/scala/chisel3/core/Module.scala b/chiselFrontend/src/main/scala/chisel3/core/Module.scala index 40102cd6..e8474e39 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/Module.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/Module.scala @@ -91,7 +91,7 @@ extends HasId { private[core] val _namespace = Builder.globalNamespace.child private[chisel3] val _commands = ArrayBuffer[Command]() - private[code] val _ids = ArrayBuffer[HasId]() + private[core] val _ids = ArrayBuffer[HasId]() Builder.currentModule = Some(this) /** Name of the instance. */ -- cgit v1.2.3 From e27079d2957c689affce66f15e9d1bf29418ad34 Mon Sep 17 00:00:00 2001 From: Jim Lawson Date: Tue, 19 Jul 2016 15:27:29 -0700 Subject: Remove explicit literal binding. --- chiselFrontend/src/main/scala/chisel3/core/Bits.scala | 4 ---- 1 file changed, 4 deletions(-) (limited to 'chiselFrontend/src') diff --git a/chiselFrontend/src/main/scala/chisel3/core/Bits.scala b/chiselFrontend/src/main/scala/chisel3/core/Bits.scala index b18a43d9..df1296dd 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/Bits.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/Bits.scala @@ -392,10 +392,6 @@ abstract trait Num[T <: Data] { sealed class UInt private[core] (width: Width, lit: Option[ULit] = None) extends Bits(width, lit) with Num[UInt] { - if (lit != None) { - this.binding = LitBinding() - - } private[chisel3] override def cloneTypeWidth(w: Width): this.type = new UInt(w).asInstanceOf[this.type] private[chisel3] def toType = s"UInt$width" -- cgit v1.2.3 From 21a3c12b309df88cdb8114c01ef35b044282d647 Mon Sep 17 00:00:00 2001 From: Jim Lawson Date: Tue, 19 Jul 2016 16:16:35 -0700 Subject: Fix LitBinding and MultiAssign tests. --- chiselFrontend/src/main/scala/chisel3/core/Bits.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'chiselFrontend/src') diff --git a/chiselFrontend/src/main/scala/chisel3/core/Bits.scala b/chiselFrontend/src/main/scala/chisel3/core/Bits.scala index df1296dd..1bdf66f1 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/Bits.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/Bits.scala @@ -530,7 +530,7 @@ private[core] sealed trait UIntFactory { val lit = ULit(value, width) val result = new UInt(lit.width, Some(lit)) // Bind result to being an Literal -// result.binding = LitBinding() + result.binding = LitBinding() result } -- cgit v1.2.3 From 01e14c8c885527861152443f1233fa77b03cb8b5 Mon Sep 17 00:00:00 2001 From: Jim Lawson Date: Tue, 19 Jul 2016 16:51:21 -0700 Subject: Merge in "complete" versions of Mem, Reg. --- .../src/main/scala/chisel3/core/Mem.scala | 31 +++++++++++++++------- .../src/main/scala/chisel3/core/Reg.scala | 22 +++++++++------ .../src/main/scala/chisel3/internal/Builder.scala | 6 ++++- 3 files changed, 41 insertions(+), 18 deletions(-) (limited to 'chiselFrontend/src') diff --git a/chiselFrontend/src/main/scala/chisel3/core/Mem.scala b/chiselFrontend/src/main/scala/chisel3/core/Mem.scala index 38f5ef14..5c1b5976 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/Mem.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/Mem.scala @@ -19,9 +19,11 @@ object Mem { * @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 mt = t.newType + Binding.bind(mt, NoDirectionBinder, "Error: fresh t") + // TODO(twigg): Remove need for this Binding + val mem = new Mem(mt, size) pushCommand(DefMemory(sourceInfo, mem, mt, size)) // TODO multi-clock mem @@ -60,7 +62,7 @@ sealed abstract class MemBase[T <: Data](t: T, val length: Int) extends HasId wi * * @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 + * @param mask write mask as a Seq 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 @@ -79,9 +81,17 @@ sealed abstract class MemBase[T <: Data](t: T, val length: Int) extends HasId wi 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 + private def makePort(sourceInfo: SourceInfo, idx: UInt, dir: MemPortDirection): T = { + Binding.checkSynthesizable(idx, s"'idx' ($idx)") + + val port = pushCommand( + DefMemPort(sourceInfo, + t.newType, Node(this), dir, idx.ref, Node(idx._parent.get.clock)) + ).id + // Bind each element of port to being a MemoryPort + Binding.bind(port, MemoryPortBinder(Builder.forcedModule), "Error: Fresh t") + port + } } /** A combinational-read, sequential-write memory. @@ -93,7 +103,7 @@ sealed abstract class MemBase[T <: Data](t: T, val length: Int) extends HasId wi * @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) +final class Mem[T <: Data] private (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") @@ -107,7 +117,10 @@ object SeqMem { 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 mt = t.newType + Binding.bind(mt, NoDirectionBinder, "Error: fresh t") + // TODO(twigg): Remove need for this Binding + val mem = new SeqMem(mt, size) pushCommand(DefSeqMemory(sourceInfo, mem, mt, size)) // TODO multi-clock mem @@ -124,7 +137,7 @@ object SeqMem { * @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) { +final class SeqMem[T <: Data] private (t: T, n: Int) extends MemBase[T](t, n) { def read(addr: UInt, enable: Bool): T = { implicit val sourceInfo = UnlocatableSourceInfo val a = Wire(UInt()) diff --git a/chiselFrontend/src/main/scala/chisel3/core/Reg.scala b/chiselFrontend/src/main/scala/chisel3/core/Reg.scala index 14ae9650..df760b5c 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/Reg.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/Reg.scala @@ -11,18 +11,17 @@ object Reg { private[core] 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) { + Binding.checkUnbound(t, s"t ($t) must be unbound Type. Try using newType?") + t.newType + } 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 + // For e.g. Reg(init=0.asUInt(k)), fix the Reg's width to k + case Some(lit) if lit.forcedWidth => init.newType case _ => init.cloneTypeWidth(Width()) } - } else { - throwException("cannot infer type") } + else throw new Exception("cannot infer type") } /** Creates a register with optional next and initialization values. @@ -59,14 +58,21 @@ init: T = null): T = { // system improves, this may be changed. val x = makeType(t, next, init) val clock = Node(x._parent.get.clock) // TODO multi-clock + + // Bind each element of x to being a Reg + Binding.bind(x, RegBinder(Builder.forcedModule), "Error: t") + if (init == null) { pushCommand(DefReg(sourceInfo, x, clock)) } else { + Binding.checkSynthesizable(init, s"'init' ($init)") pushCommand(DefRegInit(sourceInfo, x, clock, Node(x._parent.get.reset), init.ref)) } if (next != null) { + Binding.checkSynthesizable(next, s"'next' ($next)") x := next } + x } } diff --git a/chiselFrontend/src/main/scala/chisel3/internal/Builder.scala b/chiselFrontend/src/main/scala/chisel3/internal/Builder.scala index e5b85736..168e19b2 100644 --- a/chiselFrontend/src/main/scala/chisel3/internal/Builder.scala +++ b/chiselFrontend/src/main/scala/chisel3/internal/Builder.scala @@ -124,7 +124,11 @@ private[chisel3] object Builder { forcedModule._commands += c c } - def pushOp[T <: Data](cmd: DefPrim[T]): T = pushCommand(cmd).id + def pushOp[T <: Data](cmd: DefPrim[T]): T = { + // Bind each element of the returned Data to being a Op + Binding.bind(cmd.id, OpBinder(forcedModule), "Error: During op creation, fresh result") + pushCommand(cmd).id + } def errors: ErrorLog = dynamicContext.errors def error(m: => String): Unit = errors.error(m) -- cgit v1.2.3 From f81202b896d30d90075be487895befa009b11733 Mon Sep 17 00:00:00 2001 From: Jim Lawson Date: Tue, 19 Jul 2016 16:52:27 -0700 Subject: Fixes for only connectwrap version. --- chiselFrontend/src/main/scala/chisel3/core/Mem.scala | 10 +++++----- chiselFrontend/src/main/scala/chisel3/core/Reg.scala | 15 ++++++++------- 2 files changed, 13 insertions(+), 12 deletions(-) (limited to 'chiselFrontend/src') diff --git a/chiselFrontend/src/main/scala/chisel3/core/Mem.scala b/chiselFrontend/src/main/scala/chisel3/core/Mem.scala index 5c1b5976..a9854362 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/Mem.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/Mem.scala @@ -20,7 +20,7 @@ object Mem { */ 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.newType + val mt = t.cloneType Binding.bind(mt, NoDirectionBinder, "Error: fresh t") // TODO(twigg): Remove need for this Binding @@ -86,7 +86,7 @@ sealed abstract class MemBase[T <: Data](t: T, val length: Int) extends HasId wi val port = pushCommand( DefMemPort(sourceInfo, - t.newType, Node(this), dir, idx.ref, Node(idx._parent.get.clock)) + t.cloneType, Node(this), dir, idx.ref, Node(idx._parent.get.clock)) ).id // Bind each element of port to being a MemoryPort Binding.bind(port, MemoryPortBinder(Builder.forcedModule), "Error: Fresh t") @@ -103,7 +103,7 @@ sealed abstract class MemBase[T <: Data](t: T, val length: Int) extends HasId wi * @note when multiple conflicting writes are performed on a Mem element, the * result is undefined (unlike Vec, where the last assignment wins) */ -final class Mem[T <: Data] private (t: T, length: Int) extends MemBase(t, length) +sealed class Mem[T <: Data] private (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") @@ -117,7 +117,7 @@ object SeqMem { 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.newType + val mt = t.cloneType Binding.bind(mt, NoDirectionBinder, "Error: fresh t") // TODO(twigg): Remove need for this Binding @@ -137,7 +137,7 @@ object SeqMem { * @note when multiple conflicting writes are performed on a Mem element, the * result is undefined (unlike Vec, where the last assignment wins) */ -final class SeqMem[T <: Data] private (t: T, n: Int) extends MemBase[T](t, n) { +sealed class SeqMem[T <: Data] private (t: T, n: Int) extends MemBase[T](t, n) { def read(addr: UInt, enable: Bool): T = { implicit val sourceInfo = UnlocatableSourceInfo val a = Wire(UInt()) diff --git a/chiselFrontend/src/main/scala/chisel3/core/Reg.scala b/chiselFrontend/src/main/scala/chisel3/core/Reg.scala index df760b5c..b46b96ef 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/Reg.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/Reg.scala @@ -12,16 +12,18 @@ object Reg { init: T = null): T = { if (t ne null) { Binding.checkUnbound(t, s"t ($t) must be unbound Type. Try using newType?") - t.newType - } else if (next ne null) next.cloneTypeWidth(Width()) - else if (init 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=0.asUInt(k)), fix the Reg's width to k - case Some(lit) if lit.forcedWidth => init.newType + // 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") } - else throw new Exception("cannot infer type") } /** Creates a register with optional next and initialization values. @@ -72,7 +74,6 @@ init: T = null): T = { Binding.checkSynthesizable(next, s"'next' ($next)") x := next } - x } } -- cgit v1.2.3 From 28e80311f172ae4d1d477e8bb47ca3719c9a8fc5 Mon Sep 17 00:00:00 2001 From: Jim Lawson Date: Wed, 20 Jul 2016 13:28:15 -0700 Subject: Compile ok. Need to convert UInt(x) into UInt.Lit(x) or UInt.width(x) --- .../src/main/scala/chisel3/core/Aggregate.scala | 7 +++++-- chiselFrontend/src/main/scala/chisel3/core/Bits.scala | 19 ++++++++++++++----- chiselFrontend/src/main/scala/chisel3/core/Data.scala | 13 ++++++++++++- 3 files changed, 31 insertions(+), 8 deletions(-) (limited to 'chiselFrontend/src') diff --git a/chiselFrontend/src/main/scala/chisel3/core/Aggregate.scala b/chiselFrontend/src/main/scala/chisel3/core/Aggregate.scala index 1b49e163..666d8283 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/Aggregate.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/Aggregate.scala @@ -179,8 +179,11 @@ sealed class Vec[T <: Data] private (gen: => T, val length: Int) @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] + override def cloneType: this.type = { + val clone = Vec(length, gen).asInstanceOf[this.type] + clone.unBind() + clone + } private[chisel3] def toType: String = s"${sample_element.toType}[$length]" private[chisel3] lazy val flatten: IndexedSeq[Bits] = diff --git a/chiselFrontend/src/main/scala/chisel3/core/Bits.scala b/chiselFrontend/src/main/scala/chisel3/core/Bits.scala index 1bdf66f1..e8aae578 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/Bits.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/Bits.scala @@ -51,7 +51,11 @@ sealed abstract class Bits(width: Width, override val litArg: Option[LitArg]) private[chisel3] def flatten: IndexedSeq[Bits] = IndexedSeq(this) - def cloneType: this.type = cloneTypeWidth(width) + def cloneType: this.type = { + val clone = cloneTypeWidth(width) + clone.unBind() + clone + } final def tail(n: Int): UInt = macro SourceInfoTransform.nArg final def head(n: Int): UInt = macro SourceInfoTransform.nArg @@ -514,12 +518,12 @@ sealed class UInt private[core] (width: Width, lit: Option[ULit] = None) private[core] sealed trait UIntFactory { /** Create a UInt type with inferred width. */ def apply(): UInt = apply(Width()) + /** Create a UInt type or port with fixed width. */ + def apply(width: Int): UInt = apply(Width(width)) /** Create a UInt port with specified width. */ def apply(width: Width): UInt = new UInt(width) /** Create a UInt with a specified width - compatibility with Chisel2. */ - def apply(dummy: Option[Direction] = None, width: Int): UInt = apply(Width(width)) - /** Create a UInt literal with inferred width. */ - def apply(value: BigInt): UInt = apply(value, Width()) + def apply(dummy: Direction, width: Int): UInt = apply(Width(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. */ @@ -733,7 +737,12 @@ object Bool { /** Creates Bool literal. */ - def apply(x: Boolean): Bool = new Bool(Some(ULit(if (x) 1 else 0, Width(1)))) + def apply(x: Boolean): Bool = { + val result = new Bool(Some(ULit(if (x) 1 else 0, Width(1)))) + // Bind result to being an Literal + result.binding = LitBinding() + result + } } object Mux { diff --git a/chiselFrontend/src/main/scala/chisel3/core/Data.scala b/chiselFrontend/src/main/scala/chisel3/core/Data.scala index 4cc66cb5..79119114 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/Data.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/Data.scala @@ -174,6 +174,13 @@ abstract class Data extends HasId { */ @deprecated("Use asBits, which makes the reinterpret cast more explicit and actually returns Bits", "chisel3") def toBits(): UInt = SeqUtils.do_asUInt(this.flatten)(DeprecatedSourceInfo) + + protected def unBind(): Unit = { + //TODO(twigg): Do recursively for better error messages + for(elem <- this.allElements) { + elem.binding = UnboundBinding(elem.binding.direction) + } + } } object Wire { @@ -210,7 +217,11 @@ object Clock { // TODO: Document this. sealed class Clock extends Element(Width(1)) { - def cloneType: this.type = Clock().asInstanceOf[this.type] + def cloneType: this.type = { + val clone = Clock().asInstanceOf[this.type] + clone.unBind() + clone + } private[chisel3] override def flatten: IndexedSeq[Bits] = IndexedSeq() private[chisel3] def cloneTypeWidth(width: Width): this.type = cloneType private[chisel3] def toType = "Clock" -- cgit v1.2.3 From 54cd58cbb435170dd2ed67dafe1cb1d769a799e8 Mon Sep 17 00:00:00 2001 From: Jack Koenig Date: Wed, 20 Jul 2016 13:33:23 -0700 Subject: Generate better names for nodes (#190) For Chisel nodes defined in Module class-level values of type Option or Iterable, we can still use reflection to assign names based on the name of the value. This works for arbitrary nesting of Option and Iterable so long as the innermost type is HasId. Note that this excludes Maps which always have an innermost type of Tuple2[_,_]. --- .../src/main/scala/chisel3/core/Module.scala | 24 +++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) (limited to 'chiselFrontend/src') diff --git a/chiselFrontend/src/main/scala/chisel3/core/Module.scala b/chiselFrontend/src/main/scala/chisel3/core/Module.scala index cde7032d..ca91c5f8 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/Module.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/Module.scala @@ -103,10 +103,28 @@ extends HasId { val valNames = getValNames(this.getClass) def isPublicVal(m: java.lang.reflect.Method) = m.getParameterTypes.isEmpty && valNames.contains(m.getName) + + /** Recursively suggests names to supported "container" classes + * Arbitrary nestings of supported classes are allowed so long as the + * innermost element is of type HasId + * Currently supported: + * - Iterable + * - Option + * (Note that Map is Iterable[Tuple2[_,_]] and thus excluded) + */ + def nameRecursively(prefix: String, nameMe: Any): Unit = + nameMe match { + case (id: HasId) => id.suggestName(prefix) + case Some(elt) => nameRecursively(prefix, elt) + case (iter: Iterable[_]) if iter.hasDefiniteSize => + for ((elt, i) <- iter.zipWithIndex) { + nameRecursively(s"${prefix}_${i}", elt) + } + case _ => // Do nothing + } 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 (m <- methods if isPublicVal(m)) { + nameRecursively(m.getName, m.invoke(this)) } // For Module instances we haven't named, suggest the name of the Module -- cgit v1.2.3 From 2dce378deda1cc33833eb378c89a1c5415817bae Mon Sep 17 00:00:00 2001 From: Jim Lawson Date: Wed, 20 Jul 2016 14:49:35 -0700 Subject: Distinguish between ?Int.Lit and ?Int.width --- .../src/main/scala/chisel3/core/Aggregate.scala | 2 +- .../src/main/scala/chisel3/core/Bits.scala | 60 +++++++++++++++------- .../src/main/scala/chisel3/core/Mem.scala | 2 +- .../src/main/scala/chisel3/core/SeqUtils.scala | 4 +- .../src/main/scala/chisel3/core/When.scala | 4 +- 5 files changed, 47 insertions(+), 25 deletions(-) (limited to 'chiselFrontend/src') diff --git a/chiselFrontend/src/main/scala/chisel3/core/Aggregate.scala b/chiselFrontend/src/main/scala/chisel3/core/Aggregate.scala index 666d8283..a80dfec8 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/Aggregate.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/Aggregate.scala @@ -241,7 +241,7 @@ trait VecLike[T <: Data] extends collection.IndexedSeq[T] with HasId { /** 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)) + private def indexWhereHelper(p: T => Bool) = this map p zip (0 until length).map(i => UInt.Lit(i)) /** Outputs the index of the first element for which p outputs true. */ diff --git a/chiselFrontend/src/main/scala/chisel3/core/Bits.scala b/chiselFrontend/src/main/scala/chisel3/core/Bits.scala index e8aae578..3580b5f3 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/Bits.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/Bits.scala @@ -270,9 +270,9 @@ sealed abstract class Bits(width: Width, override val litArg: Option[LitArg]) def do_toBool(implicit sourceInfo: SourceInfo): Bool = { width match { - case KnownWidth(1) => this(0) - case _ => throwException(s"can't covert UInt<$width> to Bool") - } + 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 @@ -407,8 +407,8 @@ sealed class UInt private[core] (width: Width, lit: Option[ULit] = None) 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 + def do_unary_- (implicit sourceInfo: SourceInfo) : UInt = UInt.Lit(0) - this + def do_unary_-% (implicit sourceInfo: SourceInfo): UInt = UInt.Lit(0) -% this override def do_+ (that: UInt)(implicit sourceInfo: SourceInfo): UInt = this +% that override def do_- (that: UInt)(implicit sourceInfo: SourceInfo): UInt = this -% that @@ -456,8 +456,8 @@ sealed class UInt private[core] (width: Width, lit: Option[ULit] = None) 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_orR(implicit sourceInfo: SourceInfo): Bool = this != UInt.Lit(0) + def do_andR(implicit sourceInfo: SourceInfo): Bool = ~this === UInt.Lit(0) def do_xorR(implicit sourceInfo: SourceInfo): Bool = redop(sourceInfo, XorReduceOp) override def do_< (that: UInt)(implicit sourceInfo: SourceInfo): Bool = compop(sourceInfo, LessOp, that) @@ -523,14 +523,25 @@ private[core] sealed trait UIntFactory { /** Create a UInt port with specified width. */ def apply(width: Width): UInt = new UInt(width) /** Create a UInt with a specified width - compatibility with Chisel2. */ + def width(width: Int): UInt = apply(Width(width)) + /** Create a UInt port with specified width. */ + def width(width: Width): UInt = new UInt(width) + /** Create a UInt with a specified width - compatibility with Chisel2. */ def apply(dummy: Direction, width: Int): UInt = apply(Width(width)) /** Create a UInt literal with fixed width. */ - def apply(value: BigInt, width: Int): UInt = apply(value, Width(width)) + def apply(value: BigInt, width: Int): UInt = Lit(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): UInt = Lit(n) /** Create a UInt literal with specified width. */ - def apply(value: BigInt, width: Width): UInt = { + def apply(value: BigInt, width: Width): UInt = Lit(value, width) + def Lit(value: BigInt, width: Int): UInt = Lit(value, Width(width)) + /** Create a UInt literal with inferred width. */ + def Lit(value: BigInt): UInt = Lit(value, Width()) + def Lit(n: String): UInt = Lit(parse(n), parsedWidth(n)) + /** Create a UInt literal with fixed width. */ + def Lit(n: String, width: Int): UInt = Lit(parse(n), width) + /** Create a UInt literal with specified width. */ + def Lit(value: BigInt, width: Width): UInt = { val lit = ULit(value, width) val result = new UInt(lit.width, Some(lit)) // Bind result to being an Literal @@ -575,8 +586,8 @@ sealed class SInt private (width: Width, lit: Option[SLit] = None) 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 + def unary_- (implicit sourceInfo: SourceInfo): SInt = SInt.Lit(0) - this + def unary_-% (implicit sourceInfo: SourceInfo): SInt = SInt.Lit(0) -% this /** add (default - no growth) operator */ override def do_+ (that: SInt)(implicit sourceInfo: SourceInfo): SInt = @@ -643,7 +654,7 @@ sealed class SInt private (width: Width, lit: Option[SLit] = None) final def abs(): UInt = macro SourceInfoTransform.noArg - def do_abs(implicit sourceInfo: SourceInfo): UInt = Mux(this < SInt(0), (-this).asUInt, this.asUInt) + def do_abs(implicit sourceInfo: SourceInfo): UInt = Mux(this < SInt.Lit(0), (-this).asUInt, this.asUInt) override def do_<< (that: Int)(implicit sourceInfo: SourceInfo): SInt = binop(sourceInfo, SInt(this.width + that), ShiftLeftOp, that) @@ -669,14 +680,24 @@ object SInt { def apply(width: Int): SInt = apply(Width(width)) /** Create an SInt type with specified width. */ def apply(width: Width): SInt = new SInt(width) + /** Create a SInt type or port with fixed width. */ + def width(width: Int): SInt = apply(Width(width)) + /** Create an SInt type with specified width. */ + def width(width: Width): SInt = new SInt(width) /** Create an SInt literal with inferred width. */ - def apply(value: BigInt): SInt = apply(value, Width()) + def apply(value: BigInt): SInt = Lit(value) /** Create an SInt literal with fixed width. */ - def apply(value: BigInt, width: Int): SInt = apply(value, Width(width)) + def apply(value: BigInt, width: Int): SInt = Lit(value, width) /** Create an SInt literal with specified width. */ - def apply(value: BigInt, width: Width): SInt = { + def apply(value: BigInt, width: Width): SInt = Lit(value, width) + + def Lit(value: BigInt): SInt = Lit(value, Width()) + def Lit(value: BigInt, width: Int): SInt = Lit(value, Width(width)) + /** Create an SInt literal with specified width. */ + def Lit(value: BigInt, width: Width): SInt = { + val lit = SLit(value, width) val result = new SInt(lit.width, Some(lit)) // Bind result to being an Literal @@ -737,7 +758,8 @@ object Bool { /** Creates Bool literal. */ - def apply(x: Boolean): Bool = { + def apply(x: Boolean): Bool = Lit(x) + def Lit(x: Boolean): Bool = { val result = new Bool(Some(ULit(if (x) 1 else 0, Width(1)))) // Bind result to being an Literal result.binding = LitBinding() @@ -754,7 +776,7 @@ object Mux { * @param alt the value chosen when `cond` is false * @example * {{{ - * val muxOut = Mux(data_in === UInt(3), UInt(3, 4), UInt(0, 4)) + * val muxOut = Mux(data_in === UInt.Lit(3), UInt(3, 4), UInt(0, 4)) * }}} */ def apply[T <: Data](cond: Bool, con: T, alt: T): T = macro MuxTransform.apply[T] diff --git a/chiselFrontend/src/main/scala/chisel3/core/Mem.scala b/chiselFrontend/src/main/scala/chisel3/core/Mem.scala index a9854362..a4e6bee3 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/Mem.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/Mem.scala @@ -36,7 +36,7 @@ sealed abstract class MemBase[T <: Data](t: T, val length: Int) extends HasId wi /** 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)) + def apply(idx: Int): T = apply(UInt.Lit(idx)) /** Creates a read/write accessor into the memory with dynamic addressing. * See the class documentation of the memory for more detailed information. diff --git a/chiselFrontend/src/main/scala/chisel3/core/SeqUtils.scala b/chiselFrontend/src/main/scala/chisel3/core/SeqUtils.scala index 91cb9e89..c1ec6b90 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/SeqUtils.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/SeqUtils.scala @@ -25,11 +25,11 @@ private[chisel3] object SeqUtils { def do_count(in: Seq[Bool])(implicit sourceInfo: SourceInfo): UInt = { if (in.size == 0) { - UInt(0) + UInt.Lit(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))) + count(in.slice(0, in.size/2)) + (UInt.Lit(0) ## count(in.slice(in.size/2, in.size))) } } diff --git a/chiselFrontend/src/main/scala/chisel3/core/When.scala b/chiselFrontend/src/main/scala/chisel3/core/When.scala index 196e7903..7049eb82 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/When.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/When.scala @@ -18,9 +18,9 @@ object when { // scalastyle:ignore object.name * * @example * {{{ - * when ( myData === UInt(3) ) { + * when ( myData === UInt.Lit(3) ) { * // Some logic to run when myData equals 3. - * } .elsewhen ( myData === UInt(1) ) { + * } .elsewhen ( myData === UInt.Lit(1) ) { * // Some logic to run when myData equals 1. * } .otherwise { * // Some logic to run when myData is neither 3 nor 1. -- cgit v1.2.3 From 1fa57cc3f76bc3e5de7e6b943abe70becdcb2295 Mon Sep 17 00:00:00 2001 From: Jim Lawson Date: Wed, 20 Jul 2016 17:08:55 -0700 Subject: More literal/width rangling. --- chiselFrontend/src/main/scala/chisel3/core/Bits.scala | 4 ---- chiselFrontend/src/main/scala/chisel3/core/Reg.scala | 2 +- chiselFrontend/src/main/scala/chisel3/core/SeqUtils.scala | 2 +- 3 files changed, 2 insertions(+), 6 deletions(-) (limited to 'chiselFrontend/src') diff --git a/chiselFrontend/src/main/scala/chisel3/core/Bits.scala b/chiselFrontend/src/main/scala/chisel3/core/Bits.scala index 3580b5f3..ee0acd86 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/Bits.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/Bits.scala @@ -518,8 +518,6 @@ sealed class UInt private[core] (width: Width, lit: Option[ULit] = None) private[core] sealed trait UIntFactory { /** Create a UInt type with inferred width. */ def apply(): UInt = apply(Width()) - /** Create a UInt type or port with fixed width. */ - def apply(width: Int): UInt = apply(Width(width)) /** Create a UInt port with specified width. */ def apply(width: Width): UInt = new UInt(width) /** Create a UInt with a specified width - compatibility with Chisel2. */ @@ -677,8 +675,6 @@ object SInt { /** Create an SInt type with inferred width. */ def apply(): SInt = apply(Width()) /** Create a SInt type or port with fixed width. */ - def apply(width: Int): SInt = apply(Width(width)) - /** Create an SInt type with specified width. */ def apply(width: Width): SInt = new SInt(width) /** Create a SInt type or port with fixed width. */ def width(width: Int): SInt = apply(Width(width)) diff --git a/chiselFrontend/src/main/scala/chisel3/core/Reg.scala b/chiselFrontend/src/main/scala/chisel3/core/Reg.scala index b46b96ef..e0607520 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/Reg.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/Reg.scala @@ -11,7 +11,7 @@ object Reg { private[core] def makeType[T <: Data](t: T = null, next: T = null, init: T = null): T = { if (t ne null) { - Binding.checkUnbound(t, s"t ($t) must be unbound Type. Try using newType?") + Binding.checkUnbound(t, s"t ($t) must be unbound Type. Try using cloneType?") t.cloneType } else if (next ne null) { next.cloneTypeWidth(Width()) diff --git a/chiselFrontend/src/main/scala/chisel3/core/SeqUtils.scala b/chiselFrontend/src/main/scala/chisel3/core/SeqUtils.scala index c1ec6b90..b06fd7a5 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/SeqUtils.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/SeqUtils.scala @@ -51,7 +51,7 @@ private[chisel3] object SeqUtils { if (in.tail.isEmpty) { in.head._2 } else { - val masked = for ((s, i) <- in) yield Mux(s, i.toBits, Bits(0)) + val masked = for ((s, i) <- in) yield Mux(s, i.toBits, Bits.Lit(0)) val width = in.map(_._2.width).reduce(_ max _) in.head._2.cloneTypeWidth(width).fromBits(masked.reduceLeft(_|_)) } -- cgit v1.2.3 From 7c9043859994b32bb07d2fce4ae61a7a3362a1b3 Mon Sep 17 00:00:00 2001 From: Jim Lawson Date: Thu, 21 Jul 2016 17:12:06 -0700 Subject: Introduce chiselCloneType to distinguish from cloneType. Still fails one test - DirectionSpec in Direction.scala --- .../src/main/scala/chisel3/core/Aggregate.scala | 18 ++++++++-------- .../src/main/scala/chisel3/core/Bits.scala | 6 +----- .../src/main/scala/chisel3/core/Data.scala | 24 ++++++++++------------ .../src/main/scala/chisel3/core/Mem.scala | 6 +++--- .../src/main/scala/chisel3/core/Reg.scala | 4 ++-- 5 files changed, 25 insertions(+), 33 deletions(-) (limited to 'chiselFrontend/src') diff --git a/chiselFrontend/src/main/scala/chisel3/core/Aggregate.scala b/chiselFrontend/src/main/scala/chisel3/core/Aggregate.scala index a80dfec8..7707d906 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/Aggregate.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/Aggregate.scala @@ -24,10 +24,10 @@ object Vec { * * @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) + def apply[T <: Data](n: Int, gen: T): Vec[T] = new Vec(gen, 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) + def apply[T <: Data](gen: T, n: Int): Vec[T] = new Vec(gen, n) /** Creates a new [[Vec]] composed of elements of the input Seq of [[Data]] * nodes. @@ -104,12 +104,12 @@ object Vec { * @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) +sealed class Vec[T <: Data] private (gen: T, val length: Int) extends Aggregate 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) + private val self: Seq[T] = Vector.fill(length)(gen.chiselCloneType) /** * sample_element 'tracks' all changes to the elements of self. @@ -118,7 +118,7 @@ sealed class Vec[T <: Data] private (gen: => T, val length: Int) * * Needed specifically for the case when the Vec is length 0. */ - private[core] val sample_element: T = gen + private[core] val sample_element: T = gen.chiselCloneType // allElements current includes sample_element // This is somewhat weird although I think the best course of action here is @@ -157,7 +157,7 @@ sealed class Vec[T <: Data] private (gen: => T, val length: Int) */ def apply(idx: UInt): T = { Binding.checkSynthesizable(idx ,s"'idx' ($idx)") - val port = sample_element.cloneType + val port = sample_element.chiselCloneType port.setRef(this, idx) //TODO(twigg): This is a bit too magical // Bind each element of port to being whatever the base type is @@ -180,9 +180,7 @@ sealed class Vec[T <: Data] private (gen: => T, val length: Int) def write(idx: UInt, data: T): Unit = apply(idx).:=(data)(DeprecatedSourceInfo) override def cloneType: this.type = { - val clone = Vec(length, gen).asInstanceOf[this.type] - clone.unBind() - clone + Vec(length, gen).asInstanceOf[this.type] } private[chisel3] def toType: String = s"${sample_element.toType}[$length]" @@ -390,5 +388,5 @@ class Bundle extends Aggregate { } private[core] object Bundle { - val keywords = List("flip", "asInput", "asOutput", "cloneType", "toBits") + val keywords = List("flip", "asInput", "asOutput", "cloneType", "toBits", "chiselCloneType") } diff --git a/chiselFrontend/src/main/scala/chisel3/core/Bits.scala b/chiselFrontend/src/main/scala/chisel3/core/Bits.scala index ee0acd86..07c113fd 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/Bits.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/Bits.scala @@ -51,11 +51,7 @@ sealed abstract class Bits(width: Width, override val litArg: Option[LitArg]) private[chisel3] def flatten: IndexedSeq[Bits] = IndexedSeq(this) - def cloneType: this.type = { - val clone = cloneTypeWidth(width) - clone.unBind() - clone - } + def cloneType: this.type = cloneTypeWidth(width) final def tail(n: Int): UInt = macro SourceInfoTransform.nArg final def head(n: Int): UInt = macro SourceInfoTransform.nArg diff --git a/chiselFrontend/src/main/scala/chisel3/core/Data.scala b/chiselFrontend/src/main/scala/chisel3/core/Data.scala index 79119114..fee5c01c 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/Data.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/Data.scala @@ -120,6 +120,15 @@ abstract class Data extends HasId { private[chisel3] def toType: String def cloneType: this.type + def chiselCloneType: this.type = { + // Call the user-supplied cloneType method + val clone = this.cloneType + //TODO(twigg): Do recursively for better error messages + for((clone_elem, source_elem) <- clone.allElements zip this.allElements) { + clone_elem.binding = UnboundBinding(source_elem.binding.direction) + } + clone + } final def := (that: Data)(implicit sourceInfo: SourceInfo): Unit = this connect that final def <> (that: Data)(implicit sourceInfo: SourceInfo): Unit = this bulkConnect that def litArg(): Option[LitArg] = None @@ -154,7 +163,7 @@ abstract class Data extends HasId { def do_fromBits(that: Bits)(implicit sourceInfo: SourceInfo): this.type = { var i = 0 - val wire = Wire(this.cloneType) + val wire = Wire(this.chiselCloneType) val bits = if (that.width.known && that.width.get >= wire.width.get) { that @@ -174,13 +183,6 @@ abstract class Data extends HasId { */ @deprecated("Use asBits, which makes the reinterpret cast more explicit and actually returns Bits", "chisel3") def toBits(): UInt = SeqUtils.do_asUInt(this.flatten)(DeprecatedSourceInfo) - - protected def unBind(): Unit = { - //TODO(twigg): Do recursively for better error messages - for(elem <- this.allElements) { - elem.binding = UnboundBinding(elem.binding.direction) - } - } } object Wire { @@ -217,11 +219,7 @@ object Clock { // TODO: Document this. sealed class Clock extends Element(Width(1)) { - def cloneType: this.type = { - val clone = Clock().asInstanceOf[this.type] - clone.unBind() - clone - } + def cloneType: this.type = Clock().asInstanceOf[this.type] private[chisel3] override def flatten: IndexedSeq[Bits] = IndexedSeq() private[chisel3] def cloneTypeWidth(width: Width): this.type = cloneType private[chisel3] def toType = "Clock" diff --git a/chiselFrontend/src/main/scala/chisel3/core/Mem.scala b/chiselFrontend/src/main/scala/chisel3/core/Mem.scala index a4e6bee3..fd0897a2 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/Mem.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/Mem.scala @@ -20,7 +20,7 @@ object Mem { */ 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 mt = t.chiselCloneType Binding.bind(mt, NoDirectionBinder, "Error: fresh t") // TODO(twigg): Remove need for this Binding @@ -86,7 +86,7 @@ sealed abstract class MemBase[T <: Data](t: T, val length: Int) extends HasId wi val port = pushCommand( DefMemPort(sourceInfo, - t.cloneType, Node(this), dir, idx.ref, Node(idx._parent.get.clock)) + t.chiselCloneType, Node(this), dir, idx.ref, Node(idx._parent.get.clock)) ).id // Bind each element of port to being a MemoryPort Binding.bind(port, MemoryPortBinder(Builder.forcedModule), "Error: Fresh t") @@ -117,7 +117,7 @@ object SeqMem { 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 mt = t.chiselCloneType Binding.bind(mt, NoDirectionBinder, "Error: fresh t") // TODO(twigg): Remove need for this Binding diff --git a/chiselFrontend/src/main/scala/chisel3/core/Reg.scala b/chiselFrontend/src/main/scala/chisel3/core/Reg.scala index e0607520..c1693531 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/Reg.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/Reg.scala @@ -12,13 +12,13 @@ object Reg { init: T = null): T = { if (t ne null) { Binding.checkUnbound(t, s"t ($t) must be unbound Type. Try using cloneType?") - t.cloneType + t.chiselCloneType } 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 Some(lit) if lit.forcedWidth => init.chiselCloneType case _ => init.cloneTypeWidth(Width()) } } else { -- cgit v1.2.3 From 7aa05590382b0528799ad5e9f1318ce42e409793 Mon Sep 17 00:00:00 2001 From: Jim Lawson Date: Mon, 25 Jul 2016 14:06:51 -0700 Subject: Minimize differences with master. Remove .Lit(x) usage. Undo "private" scope change. Change "firing" back to "fire". Add package level NODIR definition. --- .../src/main/scala/chisel3/core/Aggregate.scala | 2 +- chiselFrontend/src/main/scala/chisel3/core/Bits.scala | 18 ++++++++++-------- chiselFrontend/src/main/scala/chisel3/core/Mem.scala | 6 +++--- .../src/main/scala/chisel3/core/SeqUtils.scala | 4 ++-- chiselFrontend/src/main/scala/chisel3/core/When.scala | 4 ++-- 5 files changed, 18 insertions(+), 16 deletions(-) (limited to 'chiselFrontend/src') diff --git a/chiselFrontend/src/main/scala/chisel3/core/Aggregate.scala b/chiselFrontend/src/main/scala/chisel3/core/Aggregate.scala index 7707d906..459a3b67 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/Aggregate.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/Aggregate.scala @@ -239,7 +239,7 @@ trait VecLike[T <: Data] extends collection.IndexedSeq[T] with HasId { /** 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.Lit(i)) + 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. */ diff --git a/chiselFrontend/src/main/scala/chisel3/core/Bits.scala b/chiselFrontend/src/main/scala/chisel3/core/Bits.scala index 20ac0e4a..6ec455ca 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/Bits.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/Bits.scala @@ -404,8 +404,8 @@ sealed class UInt private[core] (width: Width, lit: Option[ULit] = None) final def unary_- (): UInt = macro SourceInfoTransform.noArg final def unary_-% (): UInt = macro SourceInfoTransform.noArg - def do_unary_- (implicit sourceInfo: SourceInfo) : UInt = UInt.Lit(0) - this - def do_unary_-% (implicit sourceInfo: SourceInfo): UInt = UInt.Lit(0) -% this + 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 @@ -453,8 +453,8 @@ sealed class UInt private[core] (width: Width, lit: Option[ULit] = None) final def andR(): Bool = macro SourceInfoTransform.noArg final def xorR(): Bool = macro SourceInfoTransform.noArg - def do_orR(implicit sourceInfo: SourceInfo): Bool = this != UInt.Lit(0) - def do_andR(implicit sourceInfo: SourceInfo): Bool = ~this === UInt.Lit(0) + 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) @@ -523,6 +523,8 @@ private[core] sealed trait UIntFactory { def width(width: Width): UInt = new UInt(width) /** Create a UInt with a specified width - compatibility with Chisel2. */ def apply(dummy: Option[Direction] = None, width: Int): UInt = apply(Width(width)) + /** Create a UInt literal with inferred width.- compatibility with Chisel2. */ + def apply(value: BigInt): UInt = apply(value, Width()) /** Create a UInt literal with fixed width. */ def apply(value: BigInt, width: Int): UInt = Lit(value, Width(width)) /** Create a UInt literal with inferred width. */ @@ -581,8 +583,8 @@ sealed class SInt private (width: Width, lit: Option[SLit] = None) final def unary_- (): SInt = macro SourceInfoTransform.noArg final def unary_-% (): SInt = macro SourceInfoTransform.noArg - def unary_- (implicit sourceInfo: SourceInfo): SInt = SInt.Lit(0) - this - def unary_-% (implicit sourceInfo: SourceInfo): SInt = SInt.Lit(0) -% this + 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 = @@ -649,7 +651,7 @@ sealed class SInt private (width: Width, lit: Option[SLit] = None) final def abs(): UInt = macro SourceInfoTransform.noArg - def do_abs(implicit sourceInfo: SourceInfo): UInt = Mux(this < SInt.Lit(0), (-this).asUInt, this.asUInt) + 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) @@ -769,7 +771,7 @@ object Mux { * @param alt the value chosen when `cond` is false * @example * {{{ - * val muxOut = Mux(data_in === UInt.Lit(3), UInt(3, 4), UInt(0, 4)) + * 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] diff --git a/chiselFrontend/src/main/scala/chisel3/core/Mem.scala b/chiselFrontend/src/main/scala/chisel3/core/Mem.scala index fd0897a2..931a0489 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/Mem.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/Mem.scala @@ -36,7 +36,7 @@ sealed abstract class MemBase[T <: Data](t: T, val length: Int) extends HasId wi /** 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.Lit(idx)) + 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. @@ -103,7 +103,7 @@ sealed abstract class MemBase[T <: Data](t: T, val length: Int) extends HasId wi * @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] private (t: T, length: Int) extends MemBase(t, length) +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") @@ -137,7 +137,7 @@ object SeqMem { * @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] private (t: T, n: Int) extends MemBase[T](t, n) { +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()) diff --git a/chiselFrontend/src/main/scala/chisel3/core/SeqUtils.scala b/chiselFrontend/src/main/scala/chisel3/core/SeqUtils.scala index f4eec422..0872ec41 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/SeqUtils.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/SeqUtils.scala @@ -24,7 +24,7 @@ private[chisel3] object SeqUtils { def count(in: Seq[Bool]): UInt = macro SourceInfoTransform.inArg def do_count(in: Seq[Bool])(implicit sourceInfo: SourceInfo): UInt = in.size match { - case 0 => UInt.Lit(0) + case 0 => UInt(0) case 1 => in.head case n => count(in take n/2) +& count(in drop n/2) } @@ -47,7 +47,7 @@ private[chisel3] object SeqUtils { if (in.tail.isEmpty) { in.head._2 } else { - val masked = for ((s, i) <- in) yield Mux(s, i.toBits, Bits.Lit(0)) + 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 index 7049eb82..196e7903 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/When.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/When.scala @@ -18,9 +18,9 @@ object when { // scalastyle:ignore object.name * * @example * {{{ - * when ( myData === UInt.Lit(3) ) { + * when ( myData === UInt(3) ) { * // Some logic to run when myData equals 3. - * } .elsewhen ( myData === UInt.Lit(1) ) { + * } .elsewhen ( myData === UInt(1) ) { * // Some logic to run when myData equals 1. * } .otherwise { * // Some logic to run when myData is neither 3 nor 1. -- cgit v1.2.3 From e09a09e3f4e5d6d8650b1db4add96c0a5b09e8ca Mon Sep 17 00:00:00 2001 From: Jim Lawson Date: Mon, 25 Jul 2016 16:36:06 -0700 Subject: Enable current (chisel2-style) compatibility mode. --- .../src/main/scala/chisel3/core/Binding.scala | 25 ++++++++++++++++++++-- .../src/main/scala/chisel3/core/Bits.scala | 18 ++++++++++++---- .../src/main/scala/chisel3/core/Data.scala | 1 + 3 files changed, 38 insertions(+), 6 deletions(-) (limited to 'chiselFrontend/src') diff --git a/chiselFrontend/src/main/scala/chisel3/core/Binding.scala b/chiselFrontend/src/main/scala/chisel3/core/Binding.scala index d8d9ebd2..75a80e4f 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/Binding.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/Binding.scala @@ -112,17 +112,38 @@ object Binding { } // Excepts if any root element is unbound and thus not on the hardware graph - def checkSynthesizable(target: Data, error_prelude: String): Unit = + def checkSynthesizable(target: Data, error_prelude: String): Unit = { + // This is called is we support autoIOWrap + def elementOfIO(element: Data): Boolean = { + element._parent match { + case None => false + case Some(x: Module) => { + // io.flatten eliminates Clock elements, so we need to use io.allElements + val ports = x.io.allElements + val isIOElement = ports.contains(element) || element == x.clock || element == x.reset + isIOElement + } + } + } try walkToBinding( target, element => element.binding match { case SynthesizableBinding() => {} // OK - case binding => throw NotSynthesizableException + case binding => + // The following kludge is an attempt to provide backward compatibility + // It should be done at at higher level. + if (!(autoIOWrap && elementOfIO(element))) + throw NotSynthesizableException + else + Binding.bind(element, PortBinder(element._parent.get), "Error: IO") } ) catch { case BindingException(message) => throw BindingException(s"$error_prelude$message") } + } + // This should be configure by options in Driver. + private[chisel3] var autoIOWrap = true } // Location refers to 'where' in the Module hierarchy this lives diff --git a/chiselFrontend/src/main/scala/chisel3/core/Bits.scala b/chiselFrontend/src/main/scala/chisel3/core/Bits.scala index 6ec455ca..ecae7340 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/Bits.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/Bits.scala @@ -521,10 +521,6 @@ private[core] sealed trait UIntFactory { def width(width: Int): UInt = apply(Width(width)) /** Create a UInt port with specified width. */ def width(width: Width): UInt = new UInt(width) - /** Create a UInt with a specified width - compatibility with Chisel2. */ - def apply(dummy: Option[Direction] = None, width: Int): UInt = apply(Width(width)) - /** Create a UInt literal with inferred width.- compatibility with Chisel2. */ - def apply(value: BigInt): UInt = apply(value, Width()) /** Create a UInt literal with fixed width. */ def apply(value: BigInt, width: Int): UInt = Lit(value, Width(width)) /** Create a UInt literal with inferred width. */ @@ -546,6 +542,20 @@ private[core] sealed trait UIntFactory { result } + /** Create a UInt with a specified width - compatibility with Chisel2. */ + def apply(dummy: Option[Direction] = None, width: Int): UInt = apply(Width(width)) + /** Create a UInt literal with inferred width.- compatibility with Chisel2. */ + def apply(value: BigInt): UInt = apply(value, Width()) + /** Create a UInt with a specified direction and width - compatibility with Chisel2. */ + def apply(direction: Direction, width: Int): UInt = { + val result = apply(Width(width)) + direction match { + case Direction.Input => Input(result) + case Direction.Output => Output(result) + case Direction.Unspecified => result + } + } + private def parse(n: String) = { val (base, num) = n.splitAt(1) val radix = base match { diff --git a/chiselFrontend/src/main/scala/chisel3/core/Data.scala b/chiselFrontend/src/main/scala/chisel3/core/Data.scala index 9e362fa6..73470383 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/Data.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/Data.scala @@ -16,6 +16,7 @@ sealed abstract class Direction(name: String) { object Direction { object Input extends Direction("input") { override def flip: Direction = Output } object Output extends Direction("output") { override def flip: Direction = Input } + object Unspecified extends Direction("unspecified") { override def flip: Direction = Unspecified } } @deprecated("debug doesn't do anything in Chisel3 as no pruning happens in the frontend", "chisel3") -- cgit v1.2.3 From e065416d59871d790cca9d75dc9a40fcc7b52015 Mon Sep 17 00:00:00 2001 From: Jim Lawson Date: Wed, 27 Jul 2016 09:13:45 -0700 Subject: Additional compatibility code. --- .../src/main/scala/chisel3/core/Bits.scala | 21 ++++++++++++++++++++- .../src/main/scala/chisel3/core/Module.scala | 2 ++ 2 files changed, 22 insertions(+), 1 deletion(-) (limited to 'chiselFrontend/src') diff --git a/chiselFrontend/src/main/scala/chisel3/core/Bits.scala b/chiselFrontend/src/main/scala/chisel3/core/Bits.scala index ecae7340..6df85c6a 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/Bits.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/Bits.scala @@ -33,10 +33,11 @@ abstract class Element(private[core] val width: Width) extends Data { private[core] def binding = _binding /** Return the binding for some bits. */ - def dir: Direction = binding.direction.get + def dir: Direction = binding.direction.getOrElse(Direction.Unspecified) private[chisel3] final def allElements: Seq[Element] = Seq(this) def widthKnown: Boolean = width.known + def name: String = getRef.name } /** A data type for values represented by a single bitvector. Provides basic @@ -709,6 +710,15 @@ object SInt { result.binding = LitBinding() result } + /** Create a SInt with a specified direction and width - compatibility with Chisel2. */ + def apply(direction: Direction, width: Int): SInt = { + val result = apply(Width(width)) + direction match { + case Direction.Input => Input(result) + case Direction.Output => Output(result) + case Direction.Unspecified => result + } + } } // REVIEW TODO: Why does this extend UInt and not Bits? Does defining airth @@ -770,6 +780,15 @@ object Bool { result.binding = LitBinding() result } + /** Create a UInt with a specified direction and width - compatibility with Chisel2. */ + def apply(direction: Direction): Bool = { + val result = apply() + direction match { + case Direction.Input => Input(result) + case Direction.Output => Output(result) + case Direction.Unspecified => result + } + } } object Mux { diff --git a/chiselFrontend/src/main/scala/chisel3/core/Module.scala b/chiselFrontend/src/main/scala/chisel3/core/Module.scala index a593f539..ba0720a4 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/Module.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/Module.scala @@ -178,4 +178,6 @@ extends HasId { _ids.foreach(_._onModuleClose) this } + // For debuggers/testers + lazy val getPorts = computePorts } -- cgit v1.2.3 From ac5bc19b5b4a3cc631900acf9dc04386a5c5cddc Mon Sep 17 00:00:00 2001 From: Jim Lawson Date: Thu, 28 Jul 2016 17:00:12 -0700 Subject: Add missing factory constructors. --- chiselFrontend/src/main/scala/chisel3/core/Bits.scala | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) (limited to 'chiselFrontend/src') diff --git a/chiselFrontend/src/main/scala/chisel3/core/Bits.scala b/chiselFrontend/src/main/scala/chisel3/core/Bits.scala index 6df85c6a..9ef46402 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/Bits.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/Bits.scala @@ -526,6 +526,8 @@ private[core] sealed trait UIntFactory { def apply(value: BigInt, width: Int): UInt = Lit(value, Width(width)) /** Create a UInt literal with inferred width. */ def apply(n: String): UInt = Lit(n) + /** Create a UInt literal with fixed width. */ + def apply(n: String, width: Int): UInt = Lit(parse(n), width) /** Create a UInt literal with specified width. */ def apply(value: BigInt, width: Width): UInt = Lit(value, width) def Lit(value: BigInt, width: Int): UInt = Lit(value, Width(width)) @@ -544,13 +546,13 @@ private[core] sealed trait UIntFactory { } /** Create a UInt with a specified width - compatibility with Chisel2. */ - def apply(dummy: Option[Direction] = None, width: Int): UInt = apply(Width(width)) + def apply(dir: Option[Direction] = None, width: Int): UInt = apply(Width(width)) /** Create a UInt literal with inferred width.- compatibility with Chisel2. */ def apply(value: BigInt): UInt = apply(value, Width()) /** Create a UInt with a specified direction and width - compatibility with Chisel2. */ - def apply(direction: Direction, width: Int): UInt = { + def apply(dir: Direction, width: Int): UInt = { val result = apply(Width(width)) - direction match { + dir match { case Direction.Input => Input(result) case Direction.Output => Output(result) case Direction.Unspecified => result @@ -710,10 +712,12 @@ object SInt { result.binding = LitBinding() result } + /** Create a SInt with a specified width - compatibility with Chisel2. */ + def apply(dir: Option[Direction] = None, width: Int): SInt = apply(Width(width)) /** Create a SInt with a specified direction and width - compatibility with Chisel2. */ - def apply(direction: Direction, width: Int): SInt = { + def apply(dir: Direction, width: Int): SInt = { val result = apply(Width(width)) - direction match { + dir match { case Direction.Input => Input(result) case Direction.Output => Output(result) case Direction.Unspecified => result @@ -781,9 +785,9 @@ object Bool { result } /** Create a UInt with a specified direction and width - compatibility with Chisel2. */ - def apply(direction: Direction): Bool = { + def apply(dir: Direction): Bool = { val result = apply() - direction match { + dir match { case Direction.Input => Input(result) case Direction.Output => Output(result) case Direction.Unspecified => result -- cgit v1.2.3 From 8b66107bffac270be16196d5a852cf3e6808fb0a Mon Sep 17 00:00:00 2001 From: Andrew Waterman Date: Sun, 31 Jul 2016 17:05:21 -0700 Subject: Fix two deprecation warnings --- chiselFrontend/src/main/scala/chisel3/core/SeqUtils.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'chiselFrontend/src') diff --git a/chiselFrontend/src/main/scala/chisel3/core/SeqUtils.scala b/chiselFrontend/src/main/scala/chisel3/core/SeqUtils.scala index 0872ec41..63bcc87f 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/SeqUtils.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/SeqUtils.scala @@ -47,7 +47,7 @@ private[chisel3] object SeqUtils { if (in.tail.isEmpty) { in.head._2 } else { - val masked = for ((s, i) <- in) yield Mux(s, i.toBits, Bits(0)) + val masked = for ((s, i) <- in) yield Mux(s, i.asUInt, UInt(0)) val width = in.map(_._2.width).reduce(_ max _) in.head._2.cloneTypeWidth(width).fromBits(masked.reduceLeft(_|_)) } -- cgit v1.2.3 From 8b0fa7826a547f9123277119aabc58f7c75e2ca3 Mon Sep 17 00:00:00 2001 From: Andrew Waterman Date: Sun, 31 Jul 2016 17:26:11 -0700 Subject: Expose asUInt from Data Deprecating toBits removes the capability to cast an arbitrary type to UInt. While it's still possible to do so using asBits.asUInt, this creates boilerplate. (asBits is almost never useful itself.) --- chiselFrontend/src/main/scala/chisel3/core/Bits.scala | 9 --------- chiselFrontend/src/main/scala/chisel3/core/Data.scala | 12 ++++++++++++ 2 files changed, 12 insertions(+), 9 deletions(-) (limited to 'chiselFrontend/src') diff --git a/chiselFrontend/src/main/scala/chisel3/core/Bits.scala b/chiselFrontend/src/main/scala/chisel3/core/Bits.scala index 94d808a4..9cca5d9d 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/Bits.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/Bits.scala @@ -210,15 +210,6 @@ sealed abstract class Bits(dirArg: Direction, width: Width, override val litArg: 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 diff --git a/chiselFrontend/src/main/scala/chisel3/core/Data.scala b/chiselFrontend/src/main/scala/chisel3/core/Data.scala index d5704369..d31e50ff 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/Data.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/Data.scala @@ -114,6 +114,18 @@ abstract class Data(dirArg: Direction) extends HasId { */ @deprecated("Use asBits, which makes the reinterpret cast more explicit and actually returns Bits", "chisel3") def toBits(): UInt = SeqUtils.do_asUInt(this.flatten)(DeprecatedSourceInfo) + + /** Reinterpret cast to 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 + * @note Aggregates are recursively packed with the first element appearing + * in the least-significant bits of the result. + */ + final def asUInt(): UInt = macro SourceInfoTransform.noArg + + def do_asUInt(implicit sourceInfo: SourceInfo): UInt = + SeqUtils.do_asUInt(this.flatten)(sourceInfo) } object Wire { -- cgit v1.2.3 From 8e24085e112d595cfaf2dc7d54bce974498521d5 Mon Sep 17 00:00:00 2001 From: Jim Lawson Date: Thu, 4 Aug 2016 13:40:35 -0700 Subject: Deal with directions on Clocks. --- chiselFrontend/src/main/scala/chisel3/core/Data.scala | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'chiselFrontend/src') diff --git a/chiselFrontend/src/main/scala/chisel3/core/Data.scala b/chiselFrontend/src/main/scala/chisel3/core/Data.scala index 8c874070..9115d1ba 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/Data.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/Data.scala @@ -227,6 +227,14 @@ object Wire { object Clock { def apply(): Clock = new Clock + def apply(dir: Direction): Clock = { + val result = apply() + dir match { + case Direction.Input => Input(result) + case Direction.Output => Output(result) + case Direction.Unspecified => result + } + } } // TODO: Document this. -- cgit v1.2.3 From c907eabfb65cd6442e35588b095ca031e2bdad7a Mon Sep 17 00:00:00 2001 From: Andrew Waterman Date: Sun, 7 Aug 2016 17:09:42 -0700 Subject: Legalize identifier names before printing It's not entirely clear what the FIRRTL implementation supports, so I'm using the ANSI C requirements for the time being. --- .../src/main/scala/chisel3/internal/Builder.scala | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) (limited to 'chiselFrontend/src') diff --git a/chiselFrontend/src/main/scala/chisel3/internal/Builder.scala b/chiselFrontend/src/main/scala/chisel3/internal/Builder.scala index 0e0a88cc..cecbd91e 100644 --- a/chiselFrontend/src/main/scala/chisel3/internal/Builder.scala +++ b/chiselFrontend/src/main/scala/chisel3/internal/Builder.scala @@ -21,16 +21,25 @@ private[chisel3] class Namespace(parent: Option[Namespace], keywords: Set[String if (this contains tryName) rename(n) else tryName } + private def sanitize(s: String): String = { + // TODO what character set does FIRRTL truly support? using ANSI C for now + def legalStart(c: Char) = (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_' + def legal(c: Char) = legalStart(c) || (c >= '0' && c <= '9') + val res = s filter legal + if (res.isEmpty || !legalStart(res.head)) s"_$res" else res + } + def contains(elem: String): Boolean = { names.contains(elem) || parent.map(_ contains elem).getOrElse(false) } def name(elem: String): String = { - if (this contains elem) { - name(rename(elem)) + val sanitized = sanitize(elem) + if (this contains sanitized) { + name(rename(sanitized)) } else { - names(elem) = 1 - elem + names(sanitized) = 1 + sanitized } } -- cgit v1.2.3 From 2a074c828ddd8e6c20fa21d618664d50120f3d7a Mon Sep 17 00:00:00 2001 From: Andrew Waterman Date: Sun, 7 Aug 2016 17:11:24 -0700 Subject: Support Module name overrides with "override def desiredName" The API allowed this before, but not safely, as users could create name conflicts. This exposes the pre-deduplication/sanitization naming API, and closes the other one. --- chiselFrontend/src/main/scala/chisel3/core/Module.scala | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'chiselFrontend/src') diff --git a/chiselFrontend/src/main/scala/chisel3/core/Module.scala b/chiselFrontend/src/main/scala/chisel3/core/Module.scala index ca91c5f8..5af744c4 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/Module.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/Module.scala @@ -57,8 +57,11 @@ extends HasId { private[core] val _ids = ArrayBuffer[HasId]() dynamicContext.currentModule = Some(this) - /** Name of the instance. */ - val name = Builder.globalNamespace.name(getClass.getName.split('.').last) + /** Desired name of this module. */ + def desiredName = this.getClass.getName.split('.').last + + /** Legalized name of this module. */ + final val name = Builder.globalNamespace.name(desiredName) /** IO for this Module. At the Scala level (pre-FIRRTL transformations), * connections in and out of a Module may only go through `io` elements. -- cgit v1.2.3 From 8c8349e3eab69235f48826b59af8f67fe0b3e80c Mon Sep 17 00:00:00 2001 From: Jim Lawson Date: Fri, 12 Aug 2016 09:39:39 -0700 Subject: Add support for per-Module compilation options. Nothing uses these now, but when we integrate Stephen's PR200, we'll need a way to selectively enable some strict connection checks on a file by file basis. We plan to do this using package imports which will define suitable compilation options. --- .../src/main/scala/chisel3/internal/Builder.scala | 11 ++++++++--- .../src/main/scala/chisel3/internal/CompileOptions.scala | 16 ++++++++++++++++ 2 files changed, 24 insertions(+), 3 deletions(-) create mode 100644 chiselFrontend/src/main/scala/chisel3/internal/CompileOptions.scala (limited to 'chiselFrontend/src') diff --git a/chiselFrontend/src/main/scala/chisel3/internal/Builder.scala b/chiselFrontend/src/main/scala/chisel3/internal/Builder.scala index cecbd91e..68dd269c 100644 --- a/chiselFrontend/src/main/scala/chisel3/internal/Builder.scala +++ b/chiselFrontend/src/main/scala/chisel3/internal/Builder.scala @@ -97,12 +97,16 @@ private[chisel3] trait HasId { private[chisel3] def getRef: Arg = _ref.get } -private[chisel3] class DynamicContext { +private[chisel3] class DynamicContext(optionMap: Option[Map[String, String]] = None) { val idGen = new IdGen val globalNamespace = new Namespace(None, Set()) val components = ArrayBuffer[Component]() var currentModule: Option[Module] = None val errors = new ErrorLog + val compileOptions = new CompileOptions(optionMap match { + case Some(map: Map[String, String]) => map + case None => Map[String, String]() + }) } private[chisel3] object Builder { @@ -115,6 +119,7 @@ private[chisel3] object Builder { def globalNamespace: Namespace = dynamicContext.globalNamespace def components: ArrayBuffer[Component] = dynamicContext.components + def compileOptions = dynamicContext.compileOptions def pushCommand[T <: Command](c: T): T = { dynamicContext.currentModule.foreach(_._commands += c) c @@ -124,8 +129,8 @@ private[chisel3] object Builder { 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)) { + def build[T <: Module](f: => T, optionMap: Option[Map[String, String]] = None): Circuit = { + dynamicContextVar.withValue(Some(new DynamicContext(optionMap))) { errors.info("Elaborating design...") val mod = f mod.forceName(mod.name, globalNamespace) diff --git a/chiselFrontend/src/main/scala/chisel3/internal/CompileOptions.scala b/chiselFrontend/src/main/scala/chisel3/internal/CompileOptions.scala new file mode 100644 index 00000000..12789855 --- /dev/null +++ b/chiselFrontend/src/main/scala/chisel3/internal/CompileOptions.scala @@ -0,0 +1,16 @@ +// See LICENSE for license details. + +package chisel3.internal + +/** Initialize compilation options from a string map. + * + * @param optionsMap the map from "option" to "value" + */ +class CompileOptions(optionsMap: Map[String, String]) { + // The default for settings related to "strictness". + val strictDefault: String = optionsMap.getOrElse("strict", "false") + // Should Bundle connections require a strict match of fields. + // If true and the same fields aren't present in both source and sink, a MissingFieldException, + // MissingLeftFieldException, or MissingRightFieldException will be thrown. + val connectFieldsMustMatch: Boolean = optionsMap.getOrElse("connectFieldsMustMatch", strictDefault).toBoolean +} -- cgit v1.2.3 From 4ab2aa0e9209000fb0ba1299ac18db2e033f708f Mon Sep 17 00:00:00 2001 From: Jim Lawson Date: Fri, 12 Aug 2016 14:17:52 -0700 Subject: Use compileOptions to determine if Missing...FieldExceptions are thrown. --- .../src/main/scala/chisel3/core/BiConnect.scala | 16 ++++++++++++---- .../src/main/scala/chisel3/core/MonoConnect.scala | 10 +++++++--- .../src/main/scala/chisel3/internal/Builder.scala | 2 +- 3 files changed, 20 insertions(+), 8 deletions(-) (limited to 'chiselFrontend/src') diff --git a/chiselFrontend/src/main/scala/chisel3/core/BiConnect.scala b/chiselFrontend/src/main/scala/chisel3/core/BiConnect.scala index cb76159a..71de50f6 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/BiConnect.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/BiConnect.scala @@ -1,9 +1,9 @@ package chisel3.core -import chisel3.internal.Builder.pushCommand +import chisel3.internal.Builder.{compileOptions, pushCommand} import chisel3.internal.firrtl.Connect import scala.language.experimental.macros -import chisel3.internal.sourceinfo.{SourceInfo, DeprecatedSourceInfo, UnlocatableSourceInfo, WireTransform, SourceInfoTransform} +import chisel3.internal.sourceinfo._ /** * BiConnect.connect executes a bidirectional connection element-wise. @@ -69,14 +69,22 @@ object BiConnect { 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) + if(!left_b.elements.isDefinedAt(field)) { + if (compileOptions.connectFieldsMustMatch) { + 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) + case None => { + if (compileOptions.connectFieldsMustMatch) { + throw MissingRightFieldException(field) + } + } } } catch { case BiConnectException(message) => throw BiConnectException(s".$field$message") diff --git a/chiselFrontend/src/main/scala/chisel3/core/MonoConnect.scala b/chiselFrontend/src/main/scala/chisel3/core/MonoConnect.scala index 64c71cb2..bf8e7e28 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/MonoConnect.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/MonoConnect.scala @@ -1,9 +1,9 @@ package chisel3.core -import chisel3.internal.Builder.pushCommand +import chisel3.internal.Builder.{compileOptions, pushCommand} import chisel3.internal.firrtl.Connect import scala.language.experimental.macros -import chisel3.internal.sourceinfo.{SourceInfo, DeprecatedSourceInfo, UnlocatableSourceInfo, WireTransform, SourceInfoTransform} +import chisel3.internal.sourceinfo.{DeprecatedSourceInfo, SourceInfo, SourceInfoTransform, UnlocatableSourceInfo, WireTransform} /** * MonoConnect.connect executes a mono-directional connection element-wise. @@ -78,7 +78,11 @@ object MonoConnect { try { source_b.elements.get(field) match { case Some(source_sub) => connect(sourceInfo, sink_sub, source_sub, context_mod) - case None => throw MissingFieldException(field) + case None => { + if (compileOptions.connectFieldsMustMatch) { + throw MissingFieldException(field) + } + } } } catch { case MonoConnectException(message) => throw MonoConnectException(s".$field$message") diff --git a/chiselFrontend/src/main/scala/chisel3/internal/Builder.scala b/chiselFrontend/src/main/scala/chisel3/internal/Builder.scala index dddc261e..9f2b1631 100644 --- a/chiselFrontend/src/main/scala/chisel3/internal/Builder.scala +++ b/chiselFrontend/src/main/scala/chisel3/internal/Builder.scala @@ -118,6 +118,7 @@ private[chisel3] object Builder { def idGen: IdGen = dynamicContext.idGen def globalNamespace: Namespace = dynamicContext.globalNamespace def components: ArrayBuffer[Component] = dynamicContext.components + def compileOptions = dynamicContext.compileOptions def currentModule: Option[Module] = dynamicContext.currentModule def currentModule_=(target: Option[Module]): Unit = { @@ -133,7 +134,6 @@ private[chisel3] object Builder { // TODO(twigg): Ideally, binding checks and new bindings would all occur here // However, rest of frontend can't support this yet. - def compileOptions = dynamicContext.compileOptions def pushCommand[T <: Command](c: T): T = { forcedModule._commands += c c -- cgit v1.2.3 From ddb7278760029be9d960ba8bf2b06ac8a8aac767 Mon Sep 17 00:00:00 2001 From: Andrew Waterman Date: Mon, 15 Aug 2016 22:48:14 -0700 Subject: Make "def width" a private API; expose isWidthKnown instead (#257) * Make "def width" a private API; expose isWidthKnown instead Resolves #256. Since width was used to determine whether getWidth would succeed, I added def isWidthKnown: Boolean but another option would be to expose something like def widthOption: Option[Int] ...thoughts? * Document getWidth/isWidthKnown * Add widthOption for more idiomatic Scala manipulation of widths --- chiselFrontend/src/main/scala/chisel3/core/Aggregate.scala | 5 +++-- chiselFrontend/src/main/scala/chisel3/core/Bits.scala | 2 +- chiselFrontend/src/main/scala/chisel3/core/Data.scala | 8 +++++++- 3 files changed, 11 insertions(+), 4 deletions(-) (limited to 'chiselFrontend/src') diff --git a/chiselFrontend/src/main/scala/chisel3/core/Aggregate.scala b/chiselFrontend/src/main/scala/chisel3/core/Aggregate.scala index f2774a8d..15643ac8 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/Aggregate.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/Aggregate.scala @@ -16,7 +16,7 @@ import chisel3.internal.sourceinfo.{SourceInfo, DeprecatedSourceInfo, VecTransfo */ sealed abstract class Aggregate(dirArg: Direction) extends Data(dirArg) { private[core] def cloneTypeWidth(width: Width): this.type = cloneType - def width: Width = flatten.map(_.width).reduce(_ + _) + private[core] def width: Width = flatten.map(_.width).reduce(_ + _) } object Vec { @@ -373,5 +373,6 @@ class Bundle extends Aggregate(NO_DIR) { } private[core] object Bundle { - val keywords = List("flip", "asInput", "asOutput", "cloneType", "toBits") + val keywords = List("flip", "asInput", "asOutput", "cloneType", "toBits", + "widthOption") } diff --git a/chiselFrontend/src/main/scala/chisel3/core/Bits.scala b/chiselFrontend/src/main/scala/chisel3/core/Bits.scala index 9cca5d9d..015b9dfb 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/Bits.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/Bits.scala @@ -14,7 +14,7 @@ import chisel3.internal.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) +abstract class Element(dirArg: Direction, private[core] val width: Width) extends Data(dirArg) /** A data type for values represented by a single bitvector. Provides basic * bitwise operations. diff --git a/chiselFrontend/src/main/scala/chisel3/core/Data.scala b/chiselFrontend/src/main/scala/chisel3/core/Data.scala index d31e50ff..8826af51 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/Data.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/Data.scala @@ -56,6 +56,7 @@ abstract class Data(dirArg: Direction) extends HasId { private[chisel3] def ref: Arg = if (isLit) litArg.get else lref private[core] def cloneTypeWidth(width: Width): this.type private[chisel3] def toType: String + private[core] def width: Width def := (that: Data)(implicit sourceInfo: SourceInfo): Unit = this badConnect that @@ -66,8 +67,13 @@ abstract class Data(dirArg: Direction) extends HasId { def litValue(): BigInt = litArg.get.num def isLit(): Boolean = litArg.isDefined - def width: Width + /** Returns the width, in bits, if currently known. + * @throws java.util.NoSuchElementException if the width is not known. */ final def getWidth: Int = width.get + /** Returns whether the width is currently known. */ + final def isWidthKnown: Boolean = width.known + /** Returns Some(width) if the width is known, else None. */ + final def widthOption: Option[Int] = if (isWidthKnown) Some(getWidth) else None // While this being in the Data API doesn't really make sense (should be in // Aggregate, right?) this is because of an implementation limitation: -- cgit v1.2.3 From e1e7c7ea3359df1351ba979287b62458e411e846 Mon Sep 17 00:00:00 2001 From: Jim Lawson Date: Mon, 8 Aug 2016 16:54:05 -0700 Subject: Provide public SignalID trait to be used to conjure up a signal identifier. --- .../src/main/scala/chisel3/core/Module.scala | 3 +++ .../src/main/scala/chisel3/internal/Builder.scala | 21 ++++++++++++++++++++- 2 files changed, 23 insertions(+), 1 deletion(-) (limited to 'chiselFrontend/src') diff --git a/chiselFrontend/src/main/scala/chisel3/core/Module.scala b/chiselFrontend/src/main/scala/chisel3/core/Module.scala index 5af744c4..4f25515b 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/Module.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/Module.scala @@ -63,6 +63,9 @@ extends HasId { /** Legalized name of this module. */ final val name = Builder.globalNamespace.name(desiredName) + /** Signal name (for simulation). */ + override def signalName(component: Component) = name + /** IO for this Module. At the Scala level (pre-FIRRTL transformations), * connections in and out of a Module may only go through `io` elements. */ diff --git a/chiselFrontend/src/main/scala/chisel3/internal/Builder.scala b/chiselFrontend/src/main/scala/chisel3/internal/Builder.scala index cecbd91e..dd4b3264 100644 --- a/chiselFrontend/src/main/scala/chisel3/internal/Builder.scala +++ b/chiselFrontend/src/main/scala/chisel3/internal/Builder.scala @@ -55,11 +55,30 @@ private[chisel3] class IdGen { } } -private[chisel3] trait HasId { +/** Public API to Nodes. + * currently, the node's name, the full path name, and a reference to its parent. + */ +trait SignalID { + def signalName(component: Component): String + def signalPathName(component: Component, separator: String = "_"): String + def signalParent: Module +} + +private[chisel3] trait HasId extends SignalID { private[chisel3] def _onModuleClose {} // scalastyle:ignore method.name private[chisel3] val _parent = Builder.dynamicContext.currentModule _parent.foreach(_.addId(this)) + // Implementation of public methods. + override def signalParent = _parent.get + override def signalName(component: Component) = _ref.get.fullName(component) + override def signalPathName(component: Component, separator: String = "_"): String = { + _parent match { + case Some(p) => p.signalPathName(component, separator) + separator + signalName(component) + case None => signalName(component) + } + } + private[chisel3] val _id = Builder.idGen.next override def hashCode: Int = _id.toInt override def equals(that: Any): Boolean = that match { -- cgit v1.2.3 From 0744b3e5f9c0648878b97d3375cd7d88e2d0ee08 Mon Sep 17 00:00:00 2001 From: Jim Lawson Date: Wed, 10 Aug 2016 17:07:31 -0700 Subject: Add component to signature. --- chiselFrontend/src/main/scala/chisel3/core/Aggregate.scala | 3 +-- chiselFrontend/src/main/scala/chisel3/internal/Builder.scala | 9 ++++++--- 2 files changed, 7 insertions(+), 5 deletions(-) (limited to 'chiselFrontend/src') diff --git a/chiselFrontend/src/main/scala/chisel3/core/Aggregate.scala b/chiselFrontend/src/main/scala/chisel3/core/Aggregate.scala index 15643ac8..de64cb3d 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/Aggregate.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/Aggregate.scala @@ -374,5 +374,4 @@ class Bundle extends Aggregate(NO_DIR) { private[core] object Bundle { val keywords = List("flip", "asInput", "asOutput", "cloneType", "toBits", - "widthOption") -} + "widthOption", "signalName", "signalPathName", "signalParent", "signalComponent") diff --git a/chiselFrontend/src/main/scala/chisel3/internal/Builder.scala b/chiselFrontend/src/main/scala/chisel3/internal/Builder.scala index dd4b3264..21f32483 100644 --- a/chiselFrontend/src/main/scala/chisel3/internal/Builder.scala +++ b/chiselFrontend/src/main/scala/chisel3/internal/Builder.scala @@ -55,13 +55,15 @@ private[chisel3] class IdGen { } } -/** Public API to Nodes. - * currently, the node's name, the full path name, and a reference to its parent. +/** Public API to access Node/Signal names. + * currently, the node's name, the full path name, and references to its parent Module and component. + * These are only valid once the design has been elaborated, and should not be used during its construction. */ trait SignalID { def signalName(component: Component): String - def signalPathName(component: Component, separator: String = "_"): String + def signalPathName(component: Component, separator: String = "."): String def signalParent: Module + def signalComponent: Option[Component] } private[chisel3] trait HasId extends SignalID { @@ -78,6 +80,7 @@ private[chisel3] trait HasId extends SignalID { case None => signalName(component) } } + override def signalComponent: Option[Component] = None private[chisel3] val _id = Builder.idGen.next override def hashCode: Int = _id.toInt -- cgit v1.2.3 From f41f2533c55e506f7d5bf2ee0198de4d9a3dbea3 Mon Sep 17 00:00:00 2001 From: Jim Lawson Date: Tue, 16 Aug 2016 11:59:20 -0700 Subject: Reduce rocket-chip elaboration errors. --- .../src/main/scala/chisel3/core/BiConnect.scala | 24 ++++++++++++++-- .../src/main/scala/chisel3/core/Binder.scala | 3 +- .../src/main/scala/chisel3/core/Binding.scala | 33 ++++++++++++++-------- .../src/main/scala/chisel3/core/Module.scala | 14 +++++---- .../src/main/scala/chisel3/core/MonoConnect.scala | 2 ++ .../src/main/scala/chisel3/core/Reg.scala | 4 ++- .../scala/chisel3/internal/CompileOptions.scala | 6 ++++ 7 files changed, 65 insertions(+), 21 deletions(-) (limited to 'chiselFrontend/src') diff --git a/chiselFrontend/src/main/scala/chisel3/core/BiConnect.scala b/chiselFrontend/src/main/scala/chisel3/core/BiConnect.scala index 71de50f6..b7fd65a5 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/BiConnect.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/BiConnect.scala @@ -166,8 +166,28 @@ object BiConnect { 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 (Some(Input), Some(Input)) => { + if (compileOptions.portDeterminesDirection) + (left.binding, right.binding) match { + case (PortBinding(_, _), PortBinding(_, _)) => throw BothDriversException + case (PortBinding(_, _), _) => issueConnectL2R(left, right) + case (_, PortBinding(_, _)) => issueConnectR2L(left, right) + case _ => throw BothDriversException + } else { + throw BothDriversException + } + } + case (Some(Output), Some(Output)) => { + if (compileOptions.portDeterminesDirection) + (left.binding, right.binding) match { + case (PortBinding(_, _), PortBinding(_, _)) => throw BothDriversException + case (PortBinding(_, _), _) => issueConnectR2L(left, right) + case (_, PortBinding(_, _)) => issueConnectL2R(left, right) + case _ => throw BothDriversException + } else { + throw BothDriversException + } + } case (None, None) => throw UnknownDriverException } } diff --git a/chiselFrontend/src/main/scala/chisel3/core/Binder.scala b/chiselFrontend/src/main/scala/chisel3/core/Binder.scala index c7346dce..08c0519e 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/Binder.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/Binder.scala @@ -58,7 +58,8 @@ case class RegBinder(enclosure: Module) extends Binder[RegBinding] { def apply(in: UnboundBinding) = RegBinding(enclosure) } +// Notice how WireBinder uses the direction of the UnboundNode case class WireBinder(enclosure: Module) extends Binder[WireBinding] { - def apply(in: UnboundBinding) = WireBinding(enclosure) + def apply(in: UnboundBinding) = WireBinding(enclosure, in.direction) } diff --git a/chiselFrontend/src/main/scala/chisel3/core/Binding.scala b/chiselFrontend/src/main/scala/chisel3/core/Binding.scala index 75a80e4f..555ba4d5 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/Binding.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/Binding.scala @@ -1,5 +1,7 @@ package chisel3.core +import chisel3.internal.Builder.compileOptions + /** * 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 @@ -88,6 +90,8 @@ object Binding { case unbound @ UnboundBinding(_) => { element.binding = binder(unbound) } + // If autoIOWrap is enabled and we're rebinding a PortBinding, just ignore the rebinding. + case portBound @ PortBinding(_, _) if (compileOptions.autoIOWrap && binder.isInstanceOf[PortBinder]) => case binding => throw AlreadyBoundException(binding.toString) } ) @@ -113,15 +117,24 @@ object Binding { // Excepts if any root element is unbound and thus not on the hardware graph def checkSynthesizable(target: Data, error_prelude: String): Unit = { - // This is called is we support autoIOWrap - def elementOfIO(element: Data): Boolean = { + // This is called if we support autoIOWrap + def elementOfIO(element: Element): Boolean = { element._parent match { case None => false case Some(x: Module) => { - // io.flatten eliminates Clock elements, so we need to use io.allElements - val ports = x.io.allElements - val isIOElement = ports.contains(element) || element == x.clock || element == x.reset - isIOElement + // Have we defined the IO ports for this module? If not, do so now. + if (!x.ioDefined) { + x.computePorts + element.binding match { + case SynthesizableBinding() => true + case _ => false + } + } else { + // io.flatten eliminates Clock elements, so we need to use io.allElements + val ports = x.io.allElements + val isIOElement = ports.contains(element) || element == x.clock || element == x.reset + isIOElement + } } } } @@ -132,7 +145,7 @@ object Binding { case binding => // The following kludge is an attempt to provide backward compatibility // It should be done at at higher level. - if (!(autoIOWrap && elementOfIO(element))) + if (!(compileOptions.autoIOWrap && elementOfIO(element))) throw NotSynthesizableException else Binding.bind(element, PortBinder(element._parent.get), "Error: IO") @@ -142,8 +155,6 @@ object Binding { case BindingException(message) => throw BindingException(s"$error_prelude$message") } } - // This should be configure by options in Driver. - private[chisel3] var autoIOWrap = true } // Location refers to 'where' in the Module hierarchy this lives @@ -196,5 +207,5 @@ case class PortBinding(enclosure: Module, direction: Option[Direction]) case class RegBinding(enclosure: Module) extends SynthesizableBinding with ConstrainedBinding with UndirectionedBinding -case class WireBinding(enclosure: Module) - extends SynthesizableBinding with ConstrainedBinding with UndirectionedBinding +case class WireBinding(enclosure: Module, direction: Option[Direction]) + extends SynthesizableBinding with ConstrainedBinding diff --git a/chiselFrontend/src/main/scala/chisel3/core/Module.scala b/chiselFrontend/src/main/scala/chisel3/core/Module.scala index bbed4d9f..450f5b58 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/Module.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/Module.scala @@ -4,13 +4,11 @@ package chisel3.core import scala.collection.mutable.ArrayBuffer import scala.language.experimental.macros - import chisel3.internal._ -import chisel3.internal.Builder.pushCommand -import chisel3.internal.Builder.dynamicContext +import chisel3.internal.Builder._ import chisel3.internal.firrtl._ -import chisel3.internal.firrtl.{Command, Component, DefInstance, DefInvalid, ModuleIO} -import chisel3.internal.sourceinfo.{SourceInfo, InstTransform, UnlocatableSourceInfo} +import chisel3.internal.firrtl.{Command => _, _} +import chisel3.internal.sourceinfo.{InstTransform, SourceInfo, UnlocatableSourceInfo} object Module { /** A wrapper method that all Module instantiations must be wrapped in @@ -65,7 +63,7 @@ extends HasId { iodef } - private[this] var ioDefined: Boolean = false + private[core] var ioDefined: Boolean = false /** * This must wrap the datatype used to set the io field of any Module. @@ -115,6 +113,10 @@ extends HasId { private[core] def computePorts: Seq[firrtl.Port] = for((name, port) <- ports) yield { + // If we're auto-wrapping IO definitions, do so now. + if (compileOptions.autoIOWrap && name == "io" && !ioDefined) { + IO(port) + } // Port definitions need to know input or output at top-level. // By FIRRTL semantics, 'flipped' becomes an Input val direction = if(Data.isFlipped(port)) Direction.Input else Direction.Output diff --git a/chiselFrontend/src/main/scala/chisel3/core/MonoConnect.scala b/chiselFrontend/src/main/scala/chisel3/core/MonoConnect.scala index bf8e7e28..e0c95e80 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/MonoConnect.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/MonoConnect.scala @@ -118,6 +118,7 @@ object MonoConnect { // CURRENT MOD CURRENT MOD case (Some(Output), _) => issueConnect(sink, source) case (None, _) => issueConnect(sink, source) + case (_, None) if (compileOptions.internalConnectionToInputOk) => issueConnect(sink, source) case (Some(Input), _) => throw UnwritableSinkException } } @@ -134,6 +135,7 @@ object MonoConnect { case (Some(Output), Some(Output)) => issueConnect(sink, source) case (Some(Output), Some(Input)) => issueConnect(sink, source) case (_, None) => throw UnreadableSourceException + case (Some(Input), Some(Output)) if (compileOptions.tryConnectionsSwapped) => issueConnect(source, sink) case (Some(Input), _) => throw UnwritableSinkException } } diff --git a/chiselFrontend/src/main/scala/chisel3/core/Reg.scala b/chiselFrontend/src/main/scala/chisel3/core/Reg.scala index f5706833..6c357461 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/Reg.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/Reg.scala @@ -10,7 +10,9 @@ import chisel3.internal.sourceinfo.{SourceInfo, UnlocatableSourceInfo} object Reg { private[core] def makeType[T <: Data](t: T = null, next: T = null, init: T = null): T = { if (t ne null) { - Binding.checkUnbound(t, s"t ($t) must be unbound Type. Try using cloneType?") + if (Builder.compileOptions.regTypeMustBeUnbound) { + Binding.checkUnbound(t, s"t ($t) must be unbound Type. Try using cloneType?") + } t.chiselCloneType } else if (next ne null) { next.cloneTypeWidth(Width()) diff --git a/chiselFrontend/src/main/scala/chisel3/internal/CompileOptions.scala b/chiselFrontend/src/main/scala/chisel3/internal/CompileOptions.scala index 12789855..b809b8fe 100644 --- a/chiselFrontend/src/main/scala/chisel3/internal/CompileOptions.scala +++ b/chiselFrontend/src/main/scala/chisel3/internal/CompileOptions.scala @@ -9,8 +9,14 @@ package chisel3.internal class CompileOptions(optionsMap: Map[String, String]) { // The default for settings related to "strictness". val strictDefault: String = optionsMap.getOrElse("strict", "false") + val looseDefault: String = (!(strictDefault.toBoolean)).toString // Should Bundle connections require a strict match of fields. // If true and the same fields aren't present in both source and sink, a MissingFieldException, // MissingLeftFieldException, or MissingRightFieldException will be thrown. val connectFieldsMustMatch: Boolean = optionsMap.getOrElse("connectFieldsMustMatch", strictDefault).toBoolean + val regTypeMustBeUnbound: Boolean = optionsMap.getOrElse("regTypeMustBeUnbound", strictDefault).toBoolean + val autoIOWrap: Boolean = optionsMap.getOrElse("autoIOWrap", looseDefault).toBoolean + val portDeterminesDirection: Boolean = optionsMap.getOrElse("portDeterminesDirection", looseDefault).toBoolean + val internalConnectionToInputOk: Boolean = optionsMap.getOrElse("internalConnectionToInputOk", looseDefault).toBoolean + val tryConnectionsSwapped: Boolean = optionsMap.getOrElse("tryConnectionsSwapped", looseDefault).toBoolean } -- cgit v1.2.3 From 7922f8d4998dd902ee18a6e85e4a404a1f29eb3f Mon Sep 17 00:00:00 2001 From: Jim Lawson Date: Wed, 17 Aug 2016 13:30:05 -0700 Subject: Rocket-chip updates. Assume LHSItOutput if neither side is driving. Restore Wire()'s removal of direction in binding. --- chiselFrontend/src/main/scala/chisel3/core/BiConnect.scala | 8 +++++++- chiselFrontend/src/main/scala/chisel3/core/Binder.scala | 3 +-- chiselFrontend/src/main/scala/chisel3/core/Binding.scala | 4 ++-- .../src/main/scala/chisel3/internal/CompileOptions.scala | 1 + 4 files changed, 11 insertions(+), 5 deletions(-) (limited to 'chiselFrontend/src') diff --git a/chiselFrontend/src/main/scala/chisel3/core/BiConnect.scala b/chiselFrontend/src/main/scala/chisel3/core/BiConnect.scala index b7fd65a5..c40b85ad 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/BiConnect.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/BiConnect.scala @@ -188,7 +188,13 @@ object BiConnect { throw BothDriversException } } - case (None, None) => throw UnknownDriverException + case (None, None) => { + if (compileOptions.assumeLHSIsOutput) { + issueConnectR2L(left, right) + } else { + throw UnknownDriverException + } + } } } diff --git a/chiselFrontend/src/main/scala/chisel3/core/Binder.scala b/chiselFrontend/src/main/scala/chisel3/core/Binder.scala index 08c0519e..c7346dce 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/Binder.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/Binder.scala @@ -58,8 +58,7 @@ case class RegBinder(enclosure: Module) extends Binder[RegBinding] { def apply(in: UnboundBinding) = RegBinding(enclosure) } -// Notice how WireBinder uses the direction of the UnboundNode case class WireBinder(enclosure: Module) extends Binder[WireBinding] { - def apply(in: UnboundBinding) = WireBinding(enclosure, in.direction) + 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 index 555ba4d5..da678fed 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/Binding.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/Binding.scala @@ -207,5 +207,5 @@ case class PortBinding(enclosure: Module, direction: Option[Direction]) case class RegBinding(enclosure: Module) extends SynthesizableBinding with ConstrainedBinding with UndirectionedBinding -case class WireBinding(enclosure: Module, direction: Option[Direction]) - extends SynthesizableBinding with ConstrainedBinding +case class WireBinding(enclosure: Module) + extends SynthesizableBinding with ConstrainedBinding with UndirectionedBinding diff --git a/chiselFrontend/src/main/scala/chisel3/internal/CompileOptions.scala b/chiselFrontend/src/main/scala/chisel3/internal/CompileOptions.scala index b809b8fe..93879950 100644 --- a/chiselFrontend/src/main/scala/chisel3/internal/CompileOptions.scala +++ b/chiselFrontend/src/main/scala/chisel3/internal/CompileOptions.scala @@ -19,4 +19,5 @@ class CompileOptions(optionsMap: Map[String, String]) { val portDeterminesDirection: Boolean = optionsMap.getOrElse("portDeterminesDirection", looseDefault).toBoolean val internalConnectionToInputOk: Boolean = optionsMap.getOrElse("internalConnectionToInputOk", looseDefault).toBoolean val tryConnectionsSwapped: Boolean = optionsMap.getOrElse("tryConnectionsSwapped", looseDefault).toBoolean + val assumeLHSIsOutput: Boolean = optionsMap.getOrElse("assumeLHSIsOutput", looseDefault).toBoolean } -- cgit v1.2.3 From bd6e69c19aef76b6e87f7e328e03d1b93f8a1472 Mon Sep 17 00:00:00 2001 From: Jim Lawson Date: Thu, 18 Aug 2016 13:42:24 -0700 Subject: Use isFirrtlFlipped() to determine port direction. --- chiselFrontend/src/main/scala/chisel3/core/Module.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'chiselFrontend/src') diff --git a/chiselFrontend/src/main/scala/chisel3/core/Module.scala b/chiselFrontend/src/main/scala/chisel3/core/Module.scala index 450f5b58..24dabcbe 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/Module.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/Module.scala @@ -119,7 +119,7 @@ extends HasId { } // Port definitions need to know input or output at top-level. // By FIRRTL semantics, 'flipped' becomes an Input - val direction = if(Data.isFlipped(port)) Direction.Input else Direction.Output + val direction = if(Data.isFirrtlFlipped(port)) Direction.Input else Direction.Output firrtl.Port(port, direction) } -- cgit v1.2.3 From 471a9e2d15d4c968fc6eca9a86c232c6c9c9322d Mon Sep 17 00:00:00 2001 From: Jim Lawson Date: Thu, 18 Aug 2016 15:26:39 -0700 Subject: Add assumeNoDirectionIsOutput. --- .../src/main/scala/chisel3/core/MonoConnect.scala | 16 ++++++++++++++-- .../src/main/scala/chisel3/internal/CompileOptions.scala | 1 + 2 files changed, 15 insertions(+), 2 deletions(-) (limited to 'chiselFrontend/src') diff --git a/chiselFrontend/src/main/scala/chisel3/core/MonoConnect.scala b/chiselFrontend/src/main/scala/chisel3/core/MonoConnect.scala index 4ba921fa..74373e22 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/MonoConnect.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/MonoConnect.scala @@ -133,7 +133,13 @@ object MonoConnect { 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 (_, None) => { + if (compileOptions.assumeNoDirectionIsOutput) { + issueConnect(sink, source) + } else { + throw UnreadableSourceException + } + } case (Some(Input), Some(Output)) if (compileOptions.tryConnectionsSwapped) => issueConnect(source, sink) case (Some(Input), _) => throw UnwritableSinkException } @@ -165,7 +171,13 @@ object MonoConnect { 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) => { + if (compileOptions.assumeNoDirectionIsOutput) { + issueConnect(sink, source) + } else { + throw UnreadableSourceException + } + } case (None, _) => throw UnwritableSinkException } } diff --git a/chiselFrontend/src/main/scala/chisel3/internal/CompileOptions.scala b/chiselFrontend/src/main/scala/chisel3/internal/CompileOptions.scala index e040201b..912184fb 100644 --- a/chiselFrontend/src/main/scala/chisel3/internal/CompileOptions.scala +++ b/chiselFrontend/src/main/scala/chisel3/internal/CompileOptions.scala @@ -19,4 +19,5 @@ class CompileOptions(optionsMap: Map[String, String]) { val portDeterminesDirection: Boolean = optionsMap.getOrElse("portDeterminesDirection", looseDefault).toBoolean val tryConnectionsSwapped: Boolean = optionsMap.getOrElse("tryConnectionsSwapped", looseDefault).toBoolean val assumeLHSIsOutput: Boolean = optionsMap.getOrElse("assumeLHSIsOutput", looseDefault).toBoolean + val assumeNoDirectionIsOutput: Boolean = optionsMap.getOrElse("assumeNoDirectionIsOutput", looseDefault).toBoolean } -- cgit v1.2.3 From 119e6c7bb9096bbd163a439de09d4932303d0140 Mon Sep 17 00:00:00 2001 From: Jim Lawson Date: Fri, 19 Aug 2016 12:02:10 -0700 Subject: Simplify autioIOWrap code in computePorts(). As a side-effect, handle BlackBoxes correctly. --- chiselFrontend/src/main/scala/chisel3/core/Module.scala | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) (limited to 'chiselFrontend/src') diff --git a/chiselFrontend/src/main/scala/chisel3/core/Module.scala b/chiselFrontend/src/main/scala/chisel3/core/Module.scala index 24dabcbe..19063664 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/Module.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/Module.scala @@ -111,17 +111,18 @@ extends HasId { ("clk", clock), ("reset", reset), ("io", io) ) - private[core] def computePorts: Seq[firrtl.Port] = - for((name, port) <- ports) yield { - // If we're auto-wrapping IO definitions, do so now. - if (compileOptions.autoIOWrap && name == "io" && !ioDefined) { - IO(port) - } + private[core] def computePorts: Seq[firrtl.Port] = { + // If we're auto-wrapping IO definitions, do so now. + if (compileOptions.autoIOWrap && !ioDefined) { + IO(io) + } + for ((name, port) <- ports) yield { // Port definitions need to know input or output at top-level. // By FIRRTL semantics, 'flipped' becomes an Input val direction = if(Data.isFirrtlFlipped(port)) Direction.Input else Direction.Output firrtl.Port(port, direction) } + } private[core] def setupInParent(implicit sourceInfo: SourceInfo): this.type = { _parent match { -- cgit v1.2.3 From 525e5688f69f474240fe5a21d6210beb04cfef29 Mon Sep 17 00:00:00 2001 From: Jim Lawson Date: Fri, 19 Aug 2016 14:46:53 -0700 Subject: Restore immutability of direction overrides. Input, Output, and Flipped clone their inputs. --- chiselFrontend/src/main/scala/chisel3/core/Data.scala | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) (limited to 'chiselFrontend/src') diff --git a/chiselFrontend/src/main/scala/chisel3/core/Data.scala b/chiselFrontend/src/main/scala/chisel3/core/Data.scala index cb6d427d..ce7b58b4 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/Data.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/Data.scala @@ -31,27 +31,28 @@ object DataMirror { /** * Input, Output, and Flipped are used to define the directions of Module IOs. * -* Note that they do not currently call target to be a newType or cloneType. -* This is nominally for performance reasons to avoid too many extra copies when -* something is flipped multiple times. +* Note that they currently clone their source argument, including its bindings. * * Thus, an error will be thrown if these are used on bound Data */ object Input { - def apply[T<:Data](target: T): T = { + def apply[T<:Data](source: T): T = { + val target = source.chiselCloneType Data.setFirrtlDirection(target, Direction.Input) Binding.bind(target, InputBinder, "Error: Cannot set as input ") } } object Output { - def apply[T<:Data](target: T): T = { + def apply[T<:Data](source: T): T = { + val target = source.chiselCloneType Data.setFirrtlDirection(target, Direction.Output) Binding.bind(target, OutputBinder, "Error: Cannot set as output ") } } object Flipped { - def apply[T<:Data](target: T): T = { - Data.setFirrtlDirection(target, Data.getFirrtlDirection(target).flip) + def apply[T<:Data](source: T): T = { + val target = source.chiselCloneType + Data.setFirrtlDirection(target, Data.getFirrtlDirection(source).flip) Binding.bind(target, FlippedBinder, "Error: Cannot flip ") } } -- cgit v1.2.3 From 2d01fdf6f26f480cb7ed19c1365f181ea717ddc2 Mon Sep 17 00:00:00 2001 From: Donggyu Kim Date: Mon, 15 Aug 2016 18:03:12 -0700 Subject: provides signal name methods for firrtl annotation and chisel testers * signalName: returns the chirrtl name of the signal * pathName: returns the full path name of the signal from the top module * parentPathName: returns the full path of the signal's parent module instance from the top module * parentModName: returns the signal's parent **module(not instance)** name. --- .../src/main/scala/chisel3/core/Aggregate.scala | 3 +- .../src/main/scala/chisel3/core/Module.scala | 22 ++++++++++- .../src/main/scala/chisel3/internal/Builder.scala | 44 +++++++++++++--------- 3 files changed, 49 insertions(+), 20 deletions(-) (limited to 'chiselFrontend/src') diff --git a/chiselFrontend/src/main/scala/chisel3/core/Aggregate.scala b/chiselFrontend/src/main/scala/chisel3/core/Aggregate.scala index de64cb3d..82c6097f 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/Aggregate.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/Aggregate.scala @@ -374,4 +374,5 @@ class Bundle extends Aggregate(NO_DIR) { private[core] object Bundle { val keywords = List("flip", "asInput", "asOutput", "cloneType", "toBits", - "widthOption", "signalName", "signalPathName", "signalParent", "signalComponent") + "widthOption", "signalName", "signalPathName", "signalParent", "signalComponent") +} diff --git a/chiselFrontend/src/main/scala/chisel3/core/Module.scala b/chiselFrontend/src/main/scala/chisel3/core/Module.scala index 4f25515b..eb48a14d 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/Module.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/Module.scala @@ -31,7 +31,9 @@ object Module { 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) + val component = Component(m, m.name, ports, m._commands) + m._component = Some(component) + Builder.components += component pushCommand(DefInstance(sourceInfo, m, ports)) m.setupInParent(childSourceInfo) } @@ -63,8 +65,24 @@ extends HasId { /** Legalized name of this module. */ final val name = Builder.globalNamespace.name(desiredName) + /** FIRRTL Module name */ + private var _modName: Option[String] = None + private[chisel3] def setModName(name: String) = _modName = Some(name) + def modName = _modName match { + case Some(name) => name + case None => throwException("modName should be called after circuit elaboration") + } + + /** Keep component for signal names */ + private[chisel3] var _component: Option[Component] = None + + /** Signal name (for simulation). */ - override def signalName(component: Component) = name + override def signalName = + if (_parent == None) name else _component match { + case None => getRef.name + case Some(c) => getRef fullName c + } /** IO for this Module. At the Scala level (pre-FIRRTL transformations), * connections in and out of a Module may only go through `io` elements. diff --git a/chiselFrontend/src/main/scala/chisel3/internal/Builder.scala b/chiselFrontend/src/main/scala/chisel3/internal/Builder.scala index 21f32483..bf78c410 100644 --- a/chiselFrontend/src/main/scala/chisel3/internal/Builder.scala +++ b/chiselFrontend/src/main/scala/chisel3/internal/Builder.scala @@ -59,29 +59,18 @@ private[chisel3] class IdGen { * currently, the node's name, the full path name, and references to its parent Module and component. * These are only valid once the design has been elaborated, and should not be used during its construction. */ -trait SignalID { - def signalName(component: Component): String - def signalPathName(component: Component, separator: String = "."): String - def signalParent: Module - def signalComponent: Option[Component] +trait SignalId { + def signalName: String + def pathName: String + def parentPathName: String + def parentModName: String } -private[chisel3] trait HasId extends SignalID { +private[chisel3] trait HasId extends SignalId { private[chisel3] def _onModuleClose {} // scalastyle:ignore method.name private[chisel3] val _parent = Builder.dynamicContext.currentModule _parent.foreach(_.addId(this)) - // Implementation of public methods. - override def signalParent = _parent.get - override def signalName(component: Component) = _ref.get.fullName(component) - override def signalPathName(component: Component, separator: String = "_"): String = { - _parent match { - case Some(p) => p.signalPathName(component, separator) + separator + signalName(component) - case None => signalName(component) - } - } - override def signalComponent: Option[Component] = None - private[chisel3] val _id = Builder.idGen.next override def hashCode: Int = _id.toInt override def equals(that: Any): Boolean = that match { @@ -117,6 +106,27 @@ private[chisel3] trait HasId extends SignalID { private[chisel3] def setRef(parent: HasId, index: Int): Unit = setRef(Index(Node(parent), ILit(index))) private[chisel3] def setRef(parent: HasId, index: UInt): Unit = setRef(Index(Node(parent), index.ref)) private[chisel3] def getRef: Arg = _ref.get + + // Implementation of public methods. + def signalName = _parent match { + case Some(p) => p._component match { + case Some(c) => getRef fullName c + case None => throwException("signalName/pathName should be called after circuit elaboration") + } + case None => throwException("this cannot happen") + } + def pathName = _parent match { + case None => signalName + case Some(p) => s"${p.pathName}.$signalName" + } + def parentPathName = _parent match { + case Some(p) => p.pathName + case None => throwException(s"$signalName doesn't have a parent") + } + def parentModName = _parent match { + case Some(p) => p.modName + case None => throwException(s"$signalName doesn't have a parent") + } } private[chisel3] class DynamicContext { -- cgit v1.2.3 From 716de18b37c301523f8c6fb4954745aaa2a79bdb Mon Sep 17 00:00:00 2001 From: Jim Lawson Date: Tue, 23 Aug 2016 09:42:10 -0700 Subject: Swap name of compileOption "assumeNoDirectionIsOutput" to "assumeNoDirectionIsInput". --- chiselFrontend/src/main/scala/chisel3/core/MonoConnect.scala | 4 ++-- chiselFrontend/src/main/scala/chisel3/internal/CompileOptions.scala | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'chiselFrontend/src') diff --git a/chiselFrontend/src/main/scala/chisel3/core/MonoConnect.scala b/chiselFrontend/src/main/scala/chisel3/core/MonoConnect.scala index 74373e22..e3ba4801 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/MonoConnect.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/MonoConnect.scala @@ -134,7 +134,7 @@ object MonoConnect { case (Some(Output), Some(Output)) => issueConnect(sink, source) case (Some(Output), Some(Input)) => issueConnect(sink, source) case (_, None) => { - if (compileOptions.assumeNoDirectionIsOutput) { + if (compileOptions.assumeNoDirectionIsInput) { issueConnect(sink, source) } else { throw UnreadableSourceException @@ -172,7 +172,7 @@ object MonoConnect { case (Some(Input), Some(Output)) => issueConnect(sink, source) case (Some(Output), _) => throw UnwritableSinkException case (_, None) => { - if (compileOptions.assumeNoDirectionIsOutput) { + if (compileOptions.assumeNoDirectionIsInput) { issueConnect(sink, source) } else { throw UnreadableSourceException diff --git a/chiselFrontend/src/main/scala/chisel3/internal/CompileOptions.scala b/chiselFrontend/src/main/scala/chisel3/internal/CompileOptions.scala index 912184fb..a0a20020 100644 --- a/chiselFrontend/src/main/scala/chisel3/internal/CompileOptions.scala +++ b/chiselFrontend/src/main/scala/chisel3/internal/CompileOptions.scala @@ -19,5 +19,5 @@ class CompileOptions(optionsMap: Map[String, String]) { val portDeterminesDirection: Boolean = optionsMap.getOrElse("portDeterminesDirection", looseDefault).toBoolean val tryConnectionsSwapped: Boolean = optionsMap.getOrElse("tryConnectionsSwapped", looseDefault).toBoolean val assumeLHSIsOutput: Boolean = optionsMap.getOrElse("assumeLHSIsOutput", looseDefault).toBoolean - val assumeNoDirectionIsOutput: Boolean = optionsMap.getOrElse("assumeNoDirectionIsOutput", looseDefault).toBoolean + val assumeNoDirectionIsInput: Boolean = optionsMap.getOrElse("assumeNoDirectionIsInput", looseDefault).toBoolean } -- cgit v1.2.3 From f5e9a6c6e55ba19a7c1f2353d0207189062db1c9 Mon Sep 17 00:00:00 2001 From: chick Date: Wed, 24 Aug 2016 17:09:41 -0700 Subject: Per Chisel meeting. signalName -> instanceName SignalId -> InstanceId Based on Stephen's comments on PR --- chiselFrontend/src/main/scala/chisel3/core/Module.scala | 2 +- .../src/main/scala/chisel3/internal/Builder.scala | 16 ++++++++-------- 2 files changed, 9 insertions(+), 9 deletions(-) (limited to 'chiselFrontend/src') diff --git a/chiselFrontend/src/main/scala/chisel3/core/Module.scala b/chiselFrontend/src/main/scala/chisel3/core/Module.scala index eb48a14d..2426ae78 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/Module.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/Module.scala @@ -78,7 +78,7 @@ extends HasId { /** Signal name (for simulation). */ - override def signalName = + override def instanceName = if (_parent == None) name else _component match { case None => getRef.name case Some(c) => getRef fullName c diff --git a/chiselFrontend/src/main/scala/chisel3/internal/Builder.scala b/chiselFrontend/src/main/scala/chisel3/internal/Builder.scala index bf78c410..2dec78bb 100644 --- a/chiselFrontend/src/main/scala/chisel3/internal/Builder.scala +++ b/chiselFrontend/src/main/scala/chisel3/internal/Builder.scala @@ -59,14 +59,14 @@ private[chisel3] class IdGen { * currently, the node's name, the full path name, and references to its parent Module and component. * These are only valid once the design has been elaborated, and should not be used during its construction. */ -trait SignalId { - def signalName: String +trait InstanceId { + def instanceName: String def pathName: String def parentPathName: String def parentModName: String } -private[chisel3] trait HasId extends SignalId { +private[chisel3] trait HasId extends InstanceId { private[chisel3] def _onModuleClose {} // scalastyle:ignore method.name private[chisel3] val _parent = Builder.dynamicContext.currentModule _parent.foreach(_.addId(this)) @@ -108,7 +108,7 @@ private[chisel3] trait HasId extends SignalId { private[chisel3] def getRef: Arg = _ref.get // Implementation of public methods. - def signalName = _parent match { + def instanceName = _parent match { case Some(p) => p._component match { case Some(c) => getRef fullName c case None => throwException("signalName/pathName should be called after circuit elaboration") @@ -116,16 +116,16 @@ private[chisel3] trait HasId extends SignalId { case None => throwException("this cannot happen") } def pathName = _parent match { - case None => signalName - case Some(p) => s"${p.pathName}.$signalName" + case None => instanceName + case Some(p) => s"${p.pathName}.$instanceName" } def parentPathName = _parent match { case Some(p) => p.pathName - case None => throwException(s"$signalName doesn't have a parent") + case None => throwException(s"$instanceName doesn't have a parent") } def parentModName = _parent match { case Some(p) => p.modName - case None => throwException(s"$signalName doesn't have a parent") + case None => throwException(s"$instanceName doesn't have a parent") } } -- cgit v1.2.3 From f84e6ef2d68404c741ea7e2aa2f3990ebb0984ee Mon Sep 17 00:00:00 2001 From: Jim Lawson Date: Thu, 25 Aug 2016 12:16:33 -0700 Subject: Use bulkConnect in Vec,fill if any (flattened) element of the Vec has a direction associated with it. This impetus for this came out of discussion during the chisel meeting of 8/24/16 in response to errors running the chisel tutorial examples Adder test. --- chiselFrontend/src/main/scala/chisel3/core/Aggregate.scala | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) (limited to 'chiselFrontend/src') diff --git a/chiselFrontend/src/main/scala/chisel3/core/Aggregate.scala b/chiselFrontend/src/main/scala/chisel3/core/Aggregate.scala index 03c84827..5e410ebd 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/Aggregate.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/Aggregate.scala @@ -49,9 +49,16 @@ object Vec { // DummyImplicit or additional type parameter will break some code. require(!elts.isEmpty) val width = elts.map(_.width).reduce(_ max _) + // If an element has a direction associated with it, use the bulk connect operator. val vec = Wire(new Vec(elts.head.cloneTypeWidth(width), elts.length)) - for ((v, e) <- vec zip elts) - v := e + def doConnect(sink: T, source: T) = if (elts.head.flatten.exists(_.firrtlDirection != Direction.Unspecified)) { + sink bulkConnect source + } else { + sink connect source + } + for ((v, e) <- vec zip elts) { + doConnect(v, e) + } vec } -- cgit v1.2.3 From 5fcdd12fe92bd22f9cdfb8f5e39e510684b709bf Mon Sep 17 00:00:00 2001 From: Jim Lawson Date: Mon, 29 Aug 2016 09:33:51 -0700 Subject: Rename individual compile options. Stricter values are "true". Current default (not strict) values are "false". --- .../src/main/scala/chisel3/core/BiConnect.scala | 28 ++++++++++++---------- .../src/main/scala/chisel3/core/Binding.scala | 4 ++-- .../src/main/scala/chisel3/core/Module.scala | 2 +- .../src/main/scala/chisel3/core/MonoConnect.scala | 6 ++--- .../src/main/scala/chisel3/core/Reg.scala | 2 +- .../scala/chisel3/internal/CompileOptions.scala | 9 ++++--- 6 files changed, 26 insertions(+), 25 deletions(-) (limited to 'chiselFrontend/src') diff --git a/chiselFrontend/src/main/scala/chisel3/core/BiConnect.scala b/chiselFrontend/src/main/scala/chisel3/core/BiConnect.scala index c40b85ad..857b25aa 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/BiConnect.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/BiConnect.scala @@ -167,32 +167,34 @@ object BiConnect { case (None, Some(Input)) => issueConnectR2L(left, right) case (Some(Input), Some(Input)) => { - if (compileOptions.portDeterminesDirection) - (left.binding, right.binding) match { - case (PortBinding(_, _), PortBinding(_, _)) => throw BothDriversException - case (PortBinding(_, _), _) => issueConnectL2R(left, right) - case (_, PortBinding(_, _)) => issueConnectR2L(left, right) - case _ => throw BothDriversException - } else { + if (compileOptions.dontAssumeDirectionality) { throw BothDriversException + } else { + (left.binding, right.binding) match { + case (PortBinding(_, _), PortBinding(_, _)) => throw BothDriversException + case (PortBinding(_, _), _) => issueConnectL2R(left, right) + case (_, PortBinding(_, _)) => issueConnectR2L(left, right) + case _ => throw BothDriversException + } } } case (Some(Output), Some(Output)) => { - if (compileOptions.portDeterminesDirection) + if (compileOptions.dontAssumeDirectionality) { + throw BothDriversException + } else { (left.binding, right.binding) match { case (PortBinding(_, _), PortBinding(_, _)) => throw BothDriversException case (PortBinding(_, _), _) => issueConnectR2L(left, right) case (_, PortBinding(_, _)) => issueConnectL2R(left, right) case _ => throw BothDriversException - } else { - throw BothDriversException + } } } case (None, None) => { - if (compileOptions.assumeLHSIsOutput) { - issueConnectR2L(left, right) - } else { + if (compileOptions.dontAssumeDirectionality) { throw UnknownDriverException + } else { + issueConnectR2L(left, right) } } } diff --git a/chiselFrontend/src/main/scala/chisel3/core/Binding.scala b/chiselFrontend/src/main/scala/chisel3/core/Binding.scala index da678fed..a32d3ade 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/Binding.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/Binding.scala @@ -91,7 +91,7 @@ object Binding { element.binding = binder(unbound) } // If autoIOWrap is enabled and we're rebinding a PortBinding, just ignore the rebinding. - case portBound @ PortBinding(_, _) if (compileOptions.autoIOWrap && binder.isInstanceOf[PortBinder]) => + case portBound @ PortBinding(_, _) if (!compileOptions.requireIOWrap && binder.isInstanceOf[PortBinder]) => case binding => throw AlreadyBoundException(binding.toString) } ) @@ -145,7 +145,7 @@ object Binding { case binding => // The following kludge is an attempt to provide backward compatibility // It should be done at at higher level. - if (!(compileOptions.autoIOWrap && elementOfIO(element))) + if ((compileOptions.requireIOWrap || !elementOfIO(element))) throw NotSynthesizableException else Binding.bind(element, PortBinder(element._parent.get), "Error: IO") diff --git a/chiselFrontend/src/main/scala/chisel3/core/Module.scala b/chiselFrontend/src/main/scala/chisel3/core/Module.scala index 19063664..b4659a52 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/Module.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/Module.scala @@ -113,7 +113,7 @@ extends HasId { private[core] def computePorts: Seq[firrtl.Port] = { // If we're auto-wrapping IO definitions, do so now. - if (compileOptions.autoIOWrap && !ioDefined) { + if (!(compileOptions.requireIOWrap || ioDefined)) { IO(io) } for ((name, port) <- ports) yield { diff --git a/chiselFrontend/src/main/scala/chisel3/core/MonoConnect.scala b/chiselFrontend/src/main/scala/chisel3/core/MonoConnect.scala index e3ba4801..66729bac 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/MonoConnect.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/MonoConnect.scala @@ -134,13 +134,13 @@ object MonoConnect { case (Some(Output), Some(Output)) => issueConnect(sink, source) case (Some(Output), Some(Input)) => issueConnect(sink, source) case (_, None) => { - if (compileOptions.assumeNoDirectionIsInput) { + if (!compileOptions.dontAssumeDirectionality) { issueConnect(sink, source) } else { throw UnreadableSourceException } } - case (Some(Input), Some(Output)) if (compileOptions.tryConnectionsSwapped) => issueConnect(source, sink) + case (Some(Input), Some(Output)) if (!compileOptions.dontTryConnectionsSwapped) => issueConnect(source, sink) case (Some(Input), _) => throw UnwritableSinkException } } @@ -172,7 +172,7 @@ object MonoConnect { case (Some(Input), Some(Output)) => issueConnect(sink, source) case (Some(Output), _) => throw UnwritableSinkException case (_, None) => { - if (compileOptions.assumeNoDirectionIsInput) { + if (!compileOptions.dontAssumeDirectionality) { issueConnect(sink, source) } else { throw UnreadableSourceException diff --git a/chiselFrontend/src/main/scala/chisel3/core/Reg.scala b/chiselFrontend/src/main/scala/chisel3/core/Reg.scala index 6c357461..b77c9a31 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/Reg.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/Reg.scala @@ -10,7 +10,7 @@ import chisel3.internal.sourceinfo.{SourceInfo, UnlocatableSourceInfo} object Reg { private[core] def makeType[T <: Data](t: T = null, next: T = null, init: T = null): T = { if (t ne null) { - if (Builder.compileOptions.regTypeMustBeUnbound) { + if (Builder.compileOptions.declaredTypeMustBeUnbound) { Binding.checkUnbound(t, s"t ($t) must be unbound Type. Try using cloneType?") } t.chiselCloneType diff --git a/chiselFrontend/src/main/scala/chisel3/internal/CompileOptions.scala b/chiselFrontend/src/main/scala/chisel3/internal/CompileOptions.scala index a0a20020..31d441c1 100644 --- a/chiselFrontend/src/main/scala/chisel3/internal/CompileOptions.scala +++ b/chiselFrontend/src/main/scala/chisel3/internal/CompileOptions.scala @@ -15,9 +15,8 @@ class CompileOptions(optionsMap: Map[String, String]) { // MissingLeftFieldException, or MissingRightFieldException will be thrown. val connectFieldsMustMatch: Boolean = optionsMap.getOrElse("connectFieldsMustMatch", strictDefault).toBoolean val regTypeMustBeUnbound: Boolean = optionsMap.getOrElse("regTypeMustBeUnbound", strictDefault).toBoolean - val autoIOWrap: Boolean = optionsMap.getOrElse("autoIOWrap", looseDefault).toBoolean - val portDeterminesDirection: Boolean = optionsMap.getOrElse("portDeterminesDirection", looseDefault).toBoolean - val tryConnectionsSwapped: Boolean = optionsMap.getOrElse("tryConnectionsSwapped", looseDefault).toBoolean - val assumeLHSIsOutput: Boolean = optionsMap.getOrElse("assumeLHSIsOutput", looseDefault).toBoolean - val assumeNoDirectionIsInput: Boolean = optionsMap.getOrElse("assumeNoDirectionIsInput", looseDefault).toBoolean + val declaredTypeMustBeUnbound: Boolean = optionsMap.getOrElse("declaredTypeMustBeUnbound", strictDefault).toBoolean + val requireIOWrap: Boolean = optionsMap.getOrElse("requireIOWrap", strictDefault).toBoolean + val dontTryConnectionsSwapped: Boolean = optionsMap.getOrElse("dontTryConnectionsSwapped", strictDefault).toBoolean + val dontAssumeDirectionality: Boolean = optionsMap.getOrElse("dontAssumeDirectionality", strictDefault).toBoolean } -- cgit v1.2.3 From 6df3a785f8abe706838bc5b4b35c3374b6512f96 Mon Sep 17 00:00:00 2001 From: Jim Lawson Date: Mon, 29 Aug 2016 12:17:48 -0700 Subject: Pass compileOptions as an implicit Module parameter. --- .../src/main/scala/chisel3/core/BlackBox.scala | 1 + .../src/main/scala/chisel3/core/Module.scala | 3 ++ .../src/main/scala/chisel3/internal/Builder.scala | 14 ++++---- .../scala/chisel3/internal/CompileOptions.scala | 39 ++++++++++++++-------- .../src/main/scala/chisel3/notstrict.scala | 16 +++++++++ chiselFrontend/src/main/scala/chisel3/strict.scala | 16 +++++++++ 6 files changed, 68 insertions(+), 21 deletions(-) create mode 100644 chiselFrontend/src/main/scala/chisel3/notstrict.scala create mode 100644 chiselFrontend/src/main/scala/chisel3/strict.scala (limited to 'chiselFrontend/src') diff --git a/chiselFrontend/src/main/scala/chisel3/core/BlackBox.scala b/chiselFrontend/src/main/scala/chisel3/core/BlackBox.scala index f2d9558d..a9f89cbc 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/BlackBox.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/BlackBox.scala @@ -5,6 +5,7 @@ package chisel3.core import chisel3.internal.Builder.pushCommand import chisel3.internal.firrtl.{ModuleIO, DefInvalid} import chisel3.internal.sourceinfo.SourceInfo +import chisel3.NotStrict.NotStrictCompileOptions /** 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 diff --git a/chiselFrontend/src/main/scala/chisel3/core/Module.scala b/chiselFrontend/src/main/scala/chisel3/core/Module.scala index b4659a52..47003df0 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/Module.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/Module.scala @@ -9,6 +9,7 @@ import chisel3.internal.Builder._ import chisel3.internal.firrtl._ import chisel3.internal.firrtl.{Command => _, _} import chisel3.internal.sourceinfo.{InstTransform, SourceInfo, UnlocatableSourceInfo} +import chisel3.NotStrict.NotStrictCompileOptions object Module { /** A wrapper method that all Module instantiations must be wrapped in @@ -49,6 +50,7 @@ object Module { */ abstract class Module( override_clock: Option[Clock]=None, override_reset: Option[Bool]=None) + (implicit moduleCompileOptions: ExplicitCompileOptions) extends HasId { // _clock and _reset can be clock and reset in these 2ary constructors // once chisel2 compatibility issues are resolved @@ -186,4 +188,5 @@ extends HasId { } // For debuggers/testers lazy val getPorts = computePorts + val compileOptions = moduleCompileOptions } diff --git a/chiselFrontend/src/main/scala/chisel3/internal/Builder.scala b/chiselFrontend/src/main/scala/chisel3/internal/Builder.scala index 9f2b1631..9b656dea 100644 --- a/chiselFrontend/src/main/scala/chisel3/internal/Builder.scala +++ b/chiselFrontend/src/main/scala/chisel3/internal/Builder.scala @@ -97,16 +97,16 @@ private[chisel3] trait HasId { private[chisel3] def getRef: Arg = _ref.get } -private[chisel3] class DynamicContext(optionMap: Option[Map[String, String]] = None) { +private[chisel3] class DynamicContext(moduleCompileOptions: Option[ExplicitCompileOptions] = None) { val idGen = new IdGen val globalNamespace = new Namespace(None, Set()) val components = ArrayBuffer[Component]() var currentModule: Option[Module] = None val errors = new ErrorLog - val compileOptions = new CompileOptions(optionMap match { - case Some(map: Map[String, String]) => map - case None => Map[String, String]() - }) + val compileOptions = moduleCompileOptions match { + case Some(options: ExplicitCompileOptions) => options + case None => chisel3.NotStrict.NotStrictCompileOptions + } } private[chisel3] object Builder { @@ -147,8 +147,8 @@ private[chisel3] object Builder { def errors: ErrorLog = dynamicContext.errors def error(m: => String): Unit = errors.error(m) - def build[T <: Module](f: => T, optionMap: Option[Map[String, String]] = None): Circuit = { - dynamicContextVar.withValue(Some(new DynamicContext(optionMap))) { + def build[T <: Module](f: => T, moduleCompileOptions: Option[ExplicitCompileOptions] = None): Circuit = { + dynamicContextVar.withValue(Some(new DynamicContext(moduleCompileOptions))) { errors.info("Elaborating design...") val mod = f mod.forceName(mod.name, globalNamespace) diff --git a/chiselFrontend/src/main/scala/chisel3/internal/CompileOptions.scala b/chiselFrontend/src/main/scala/chisel3/internal/CompileOptions.scala index 31d441c1..2890f6dc 100644 --- a/chiselFrontend/src/main/scala/chisel3/internal/CompileOptions.scala +++ b/chiselFrontend/src/main/scala/chisel3/internal/CompileOptions.scala @@ -2,21 +2,32 @@ package chisel3.internal -/** Initialize compilation options from a string map. - * - * @param optionsMap the map from "option" to "value" - */ -class CompileOptions(optionsMap: Map[String, String]) { - // The default for settings related to "strictness". - val strictDefault: String = optionsMap.getOrElse("strict", "false") - val looseDefault: String = (!(strictDefault.toBoolean)).toString +trait CompileOptions { // Should Bundle connections require a strict match of fields. // If true and the same fields aren't present in both source and sink, a MissingFieldException, // MissingLeftFieldException, or MissingRightFieldException will be thrown. - val connectFieldsMustMatch: Boolean = optionsMap.getOrElse("connectFieldsMustMatch", strictDefault).toBoolean - val regTypeMustBeUnbound: Boolean = optionsMap.getOrElse("regTypeMustBeUnbound", strictDefault).toBoolean - val declaredTypeMustBeUnbound: Boolean = optionsMap.getOrElse("declaredTypeMustBeUnbound", strictDefault).toBoolean - val requireIOWrap: Boolean = optionsMap.getOrElse("requireIOWrap", strictDefault).toBoolean - val dontTryConnectionsSwapped: Boolean = optionsMap.getOrElse("dontTryConnectionsSwapped", strictDefault).toBoolean - val dontAssumeDirectionality: Boolean = optionsMap.getOrElse("dontAssumeDirectionality", strictDefault).toBoolean + val connectFieldsMustMatch: Boolean + val declaredTypeMustBeUnbound: Boolean + val requireIOWrap: Boolean + val dontTryConnectionsSwapped: Boolean + val dontAssumeDirectionality: Boolean } + +trait ExplicitCompileOptions extends CompileOptions + +///** Initialize compilation options from a string map. +// * +// * @param optionsMap the map from "option" to "value" +// */ +//class CompileOptions(optionsMap: Map[String, String]) { +// // The default for settings related to "strictness". +// val strictDefault: String = optionsMap.getOrElse("strict", "false") +// // Should Bundle connections require a strict match of fields. +// // If true and the same fields aren't present in both source and sink, a MissingFieldException, +// // MissingLeftFieldException, or MissingRightFieldException will be thrown. +// val connectFieldsMustMatch: Boolean = optionsMap.getOrElse("connectFieldsMustMatch", strictDefault).toBoolean +// val declaredTypeMustBeUnbound: Boolean = optionsMap.getOrElse("declaredTypeMustBeUnbound", strictDefault).toBoolean +// val requireIOWrap: Boolean = optionsMap.getOrElse("requireIOWrap", strictDefault).toBoolean +// val dontTryConnectionsSwapped: Boolean = optionsMap.getOrElse("dontTryConnectionsSwapped", strictDefault).toBoolean +// val dontAssumeDirectionality: Boolean = optionsMap.getOrElse("dontAssumeDirectionality", strictDefault).toBoolean +//} diff --git a/chiselFrontend/src/main/scala/chisel3/notstrict.scala b/chiselFrontend/src/main/scala/chisel3/notstrict.scala new file mode 100644 index 00000000..dc4bf807 --- /dev/null +++ b/chiselFrontend/src/main/scala/chisel3/notstrict.scala @@ -0,0 +1,16 @@ +// See LICENSE for license details. + +package chisel3 + +import chisel3.internal.ExplicitCompileOptions + + +object NotStrict { + implicit object NotStrictCompileOptions extends ExplicitCompileOptions { + val connectFieldsMustMatch = false + val declaredTypeMustBeUnbound = false + val requireIOWrap = false + val dontTryConnectionsSwapped = false + val dontAssumeDirectionality = false + } +} diff --git a/chiselFrontend/src/main/scala/chisel3/strict.scala b/chiselFrontend/src/main/scala/chisel3/strict.scala new file mode 100644 index 00000000..f6db8765 --- /dev/null +++ b/chiselFrontend/src/main/scala/chisel3/strict.scala @@ -0,0 +1,16 @@ +// See LICENSE for license details. + +package chisel3 + +import chisel3.internal.ExplicitCompileOptions + + +object Strict { + implicit object StrictCompileOptions extends ExplicitCompileOptions { + val connectFieldsMustMatch = true + val declaredTypeMustBeUnbound = true + val requireIOWrap = true + val dontTryConnectionsSwapped = true + val dontAssumeDirectionality = true + } +} -- cgit v1.2.3 From 62817134d222747f1eab34626fe7b1bb13b9f6df Mon Sep 17 00:00:00 2001 From: Jim Lawson Date: Mon, 29 Aug 2016 13:45:05 -0700 Subject: Rename CompileOptions implicit objects. --- chiselFrontend/src/main/scala/chisel3/core/BlackBox.scala | 2 +- chiselFrontend/src/main/scala/chisel3/core/Module.scala | 2 +- chiselFrontend/src/main/scala/chisel3/internal/Builder.scala | 2 +- chiselFrontend/src/main/scala/chisel3/notstrict.scala | 2 +- chiselFrontend/src/main/scala/chisel3/strict.scala | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) (limited to 'chiselFrontend/src') diff --git a/chiselFrontend/src/main/scala/chisel3/core/BlackBox.scala b/chiselFrontend/src/main/scala/chisel3/core/BlackBox.scala index a9f89cbc..7b0cf3f7 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/BlackBox.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/BlackBox.scala @@ -5,7 +5,7 @@ package chisel3.core import chisel3.internal.Builder.pushCommand import chisel3.internal.firrtl.{ModuleIO, DefInvalid} import chisel3.internal.sourceinfo.SourceInfo -import chisel3.NotStrict.NotStrictCompileOptions +import chisel3.NotStrict.CompileOptions /** 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 diff --git a/chiselFrontend/src/main/scala/chisel3/core/Module.scala b/chiselFrontend/src/main/scala/chisel3/core/Module.scala index 47003df0..2cfc6c6a 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/Module.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/Module.scala @@ -9,7 +9,7 @@ import chisel3.internal.Builder._ import chisel3.internal.firrtl._ import chisel3.internal.firrtl.{Command => _, _} import chisel3.internal.sourceinfo.{InstTransform, SourceInfo, UnlocatableSourceInfo} -import chisel3.NotStrict.NotStrictCompileOptions +import chisel3.NotStrict.CompileOptions object Module { /** A wrapper method that all Module instantiations must be wrapped in diff --git a/chiselFrontend/src/main/scala/chisel3/internal/Builder.scala b/chiselFrontend/src/main/scala/chisel3/internal/Builder.scala index 9b656dea..3191e384 100644 --- a/chiselFrontend/src/main/scala/chisel3/internal/Builder.scala +++ b/chiselFrontend/src/main/scala/chisel3/internal/Builder.scala @@ -105,7 +105,7 @@ private[chisel3] class DynamicContext(moduleCompileOptions: Option[ExplicitCompi val errors = new ErrorLog val compileOptions = moduleCompileOptions match { case Some(options: ExplicitCompileOptions) => options - case None => chisel3.NotStrict.NotStrictCompileOptions + case None => chisel3.NotStrict.CompileOptions } } diff --git a/chiselFrontend/src/main/scala/chisel3/notstrict.scala b/chiselFrontend/src/main/scala/chisel3/notstrict.scala index dc4bf807..bb390e7c 100644 --- a/chiselFrontend/src/main/scala/chisel3/notstrict.scala +++ b/chiselFrontend/src/main/scala/chisel3/notstrict.scala @@ -6,7 +6,7 @@ import chisel3.internal.ExplicitCompileOptions object NotStrict { - implicit object NotStrictCompileOptions extends ExplicitCompileOptions { + implicit object CompileOptions extends ExplicitCompileOptions { val connectFieldsMustMatch = false val declaredTypeMustBeUnbound = false val requireIOWrap = false diff --git a/chiselFrontend/src/main/scala/chisel3/strict.scala b/chiselFrontend/src/main/scala/chisel3/strict.scala index f6db8765..70240429 100644 --- a/chiselFrontend/src/main/scala/chisel3/strict.scala +++ b/chiselFrontend/src/main/scala/chisel3/strict.scala @@ -6,7 +6,7 @@ import chisel3.internal.ExplicitCompileOptions object Strict { - implicit object StrictCompileOptions extends ExplicitCompileOptions { + implicit object CompileOptions extends ExplicitCompileOptions { val connectFieldsMustMatch = true val declaredTypeMustBeUnbound = true val requireIOWrap = true -- cgit v1.2.3 From 1973e4d7333e2c57be4bcb7204210ecafdacab93 Mon Sep 17 00:00:00 2001 From: Jim Lawson Date: Mon, 29 Aug 2016 17:04:51 -0700 Subject: Check module-specific compile options. Import chisel3.NotStrict.CompileOptions in Chisel package. Add CompileOptions tests. --- chiselFrontend/src/main/scala/chisel3/core/BiConnect.scala | 12 +++++++----- chiselFrontend/src/main/scala/chisel3/core/Binding.scala | 6 +++--- chiselFrontend/src/main/scala/chisel3/core/MonoConnect.scala | 8 ++++---- chiselFrontend/src/main/scala/chisel3/core/Reg.scala | 2 +- 4 files changed, 15 insertions(+), 13 deletions(-) (limited to 'chiselFrontend/src') diff --git a/chiselFrontend/src/main/scala/chisel3/core/BiConnect.scala b/chiselFrontend/src/main/scala/chisel3/core/BiConnect.scala index 857b25aa..969e5654 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/BiConnect.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/BiConnect.scala @@ -1,3 +1,5 @@ +// See LICENSE for license details. + package chisel3.core import chisel3.internal.Builder.{compileOptions, pushCommand} @@ -70,7 +72,7 @@ object BiConnect { // Verify right has no extra fields that left doesn't have for((field, right_sub) <- right_b.elements) { if(!left_b.elements.isDefinedAt(field)) { - if (compileOptions.connectFieldsMustMatch) { + if (compileOptions.connectFieldsMustMatch || context_mod.compileOptions.connectFieldsMustMatch) { throw MissingLeftFieldException(field) } } @@ -81,7 +83,7 @@ object BiConnect { right_b.elements.get(field) match { case Some(right_sub) => connect(sourceInfo, left_sub, right_sub, context_mod) case None => { - if (compileOptions.connectFieldsMustMatch) { + if (compileOptions.connectFieldsMustMatch || context_mod.compileOptions.connectFieldsMustMatch) { throw MissingRightFieldException(field) } } @@ -167,7 +169,7 @@ object BiConnect { case (None, Some(Input)) => issueConnectR2L(left, right) case (Some(Input), Some(Input)) => { - if (compileOptions.dontAssumeDirectionality) { + if (compileOptions.dontAssumeDirectionality || context_mod.compileOptions.dontAssumeDirectionality) { throw BothDriversException } else { (left.binding, right.binding) match { @@ -179,7 +181,7 @@ object BiConnect { } } case (Some(Output), Some(Output)) => { - if (compileOptions.dontAssumeDirectionality) { + if (compileOptions.dontAssumeDirectionality || context_mod.compileOptions.dontAssumeDirectionality) { throw BothDriversException } else { (left.binding, right.binding) match { @@ -191,7 +193,7 @@ object BiConnect { } } case (None, None) => { - if (compileOptions.dontAssumeDirectionality) { + if (compileOptions.dontAssumeDirectionality || context_mod.compileOptions.dontAssumeDirectionality) { throw UnknownDriverException } else { issueConnectR2L(left, right) diff --git a/chiselFrontend/src/main/scala/chisel3/core/Binding.scala b/chiselFrontend/src/main/scala/chisel3/core/Binding.scala index a32d3ade..b36794f1 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/Binding.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/Binding.scala @@ -1,6 +1,6 @@ package chisel3.core -import chisel3.internal.Builder.compileOptions +import chisel3.internal.Builder.{compileOptions, forcedModule} /** * The purpose of a Binding is to indicate what type of hardware 'entity' a @@ -91,7 +91,7 @@ object Binding { element.binding = binder(unbound) } // If autoIOWrap is enabled and we're rebinding a PortBinding, just ignore the rebinding. - case portBound @ PortBinding(_, _) if (!compileOptions.requireIOWrap && binder.isInstanceOf[PortBinder]) => + case portBound @ PortBinding(_, _) if (!(compileOptions.requireIOWrap || forcedModule.compileOptions.requireIOWrap)&& binder.isInstanceOf[PortBinder]) => case binding => throw AlreadyBoundException(binding.toString) } ) @@ -145,7 +145,7 @@ object Binding { case binding => // The following kludge is an attempt to provide backward compatibility // It should be done at at higher level. - if ((compileOptions.requireIOWrap || !elementOfIO(element))) + if ((compileOptions.requireIOWrap || forcedModule.compileOptions.requireIOWrap || !elementOfIO(element))) throw NotSynthesizableException else Binding.bind(element, PortBinder(element._parent.get), "Error: IO") diff --git a/chiselFrontend/src/main/scala/chisel3/core/MonoConnect.scala b/chiselFrontend/src/main/scala/chisel3/core/MonoConnect.scala index 66729bac..41754827 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/MonoConnect.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/MonoConnect.scala @@ -79,7 +79,7 @@ object MonoConnect { source_b.elements.get(field) match { case Some(source_sub) => connect(sourceInfo, sink_sub, source_sub, context_mod) case None => { - if (compileOptions.connectFieldsMustMatch) { + if (compileOptions.connectFieldsMustMatch || context_mod.compileOptions.connectFieldsMustMatch) { throw MissingFieldException(field) } } @@ -134,13 +134,13 @@ object MonoConnect { case (Some(Output), Some(Output)) => issueConnect(sink, source) case (Some(Output), Some(Input)) => issueConnect(sink, source) case (_, None) => { - if (!compileOptions.dontAssumeDirectionality) { + if (!(compileOptions.dontAssumeDirectionality || context_mod.compileOptions.dontAssumeDirectionality)) { issueConnect(sink, source) } else { throw UnreadableSourceException } } - case (Some(Input), Some(Output)) if (!compileOptions.dontTryConnectionsSwapped) => issueConnect(source, sink) + case (Some(Input), Some(Output)) if (!(compileOptions.dontTryConnectionsSwapped || context_mod.compileOptions.dontTryConnectionsSwapped)) => issueConnect(source, sink) case (Some(Input), _) => throw UnwritableSinkException } } @@ -172,7 +172,7 @@ object MonoConnect { case (Some(Input), Some(Output)) => issueConnect(sink, source) case (Some(Output), _) => throw UnwritableSinkException case (_, None) => { - if (!compileOptions.dontAssumeDirectionality) { + if (!(compileOptions.dontAssumeDirectionality || context_mod.compileOptions.dontAssumeDirectionality)) { issueConnect(sink, source) } else { throw UnreadableSourceException diff --git a/chiselFrontend/src/main/scala/chisel3/core/Reg.scala b/chiselFrontend/src/main/scala/chisel3/core/Reg.scala index b77c9a31..36c88245 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/Reg.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/Reg.scala @@ -10,7 +10,7 @@ import chisel3.internal.sourceinfo.{SourceInfo, UnlocatableSourceInfo} object Reg { private[core] def makeType[T <: Data](t: T = null, next: T = null, init: T = null): T = { if (t ne null) { - if (Builder.compileOptions.declaredTypeMustBeUnbound) { + if (Builder.compileOptions.declaredTypeMustBeUnbound || Builder.forcedModule.compileOptions.declaredTypeMustBeUnbound) { Binding.checkUnbound(t, s"t ($t) must be unbound Type. Try using cloneType?") } t.chiselCloneType -- cgit v1.2.3 From 55719f690e637700579867edb8f90fae4d3a42ef Mon Sep 17 00:00:00 2001 From: Jim Lawson Date: Tue, 30 Aug 2016 10:08:44 -0700 Subject: Use correct case for Strict/NotStrict compile options. --- chiselFrontend/src/main/scala/chisel3/NotStrict.scala | 16 ++++++++++++++++ chiselFrontend/src/main/scala/chisel3/Strict.scala | 16 ++++++++++++++++ chiselFrontend/src/main/scala/chisel3/notstrict.scala | 16 ---------------- chiselFrontend/src/main/scala/chisel3/strict.scala | 16 ---------------- 4 files changed, 32 insertions(+), 32 deletions(-) create mode 100644 chiselFrontend/src/main/scala/chisel3/NotStrict.scala create mode 100644 chiselFrontend/src/main/scala/chisel3/Strict.scala delete mode 100644 chiselFrontend/src/main/scala/chisel3/notstrict.scala delete mode 100644 chiselFrontend/src/main/scala/chisel3/strict.scala (limited to 'chiselFrontend/src') diff --git a/chiselFrontend/src/main/scala/chisel3/NotStrict.scala b/chiselFrontend/src/main/scala/chisel3/NotStrict.scala new file mode 100644 index 00000000..bb390e7c --- /dev/null +++ b/chiselFrontend/src/main/scala/chisel3/NotStrict.scala @@ -0,0 +1,16 @@ +// See LICENSE for license details. + +package chisel3 + +import chisel3.internal.ExplicitCompileOptions + + +object NotStrict { + implicit object CompileOptions extends ExplicitCompileOptions { + val connectFieldsMustMatch = false + val declaredTypeMustBeUnbound = false + val requireIOWrap = false + val dontTryConnectionsSwapped = false + val dontAssumeDirectionality = false + } +} diff --git a/chiselFrontend/src/main/scala/chisel3/Strict.scala b/chiselFrontend/src/main/scala/chisel3/Strict.scala new file mode 100644 index 00000000..70240429 --- /dev/null +++ b/chiselFrontend/src/main/scala/chisel3/Strict.scala @@ -0,0 +1,16 @@ +// See LICENSE for license details. + +package chisel3 + +import chisel3.internal.ExplicitCompileOptions + + +object Strict { + implicit object CompileOptions extends ExplicitCompileOptions { + val connectFieldsMustMatch = true + val declaredTypeMustBeUnbound = true + val requireIOWrap = true + val dontTryConnectionsSwapped = true + val dontAssumeDirectionality = true + } +} diff --git a/chiselFrontend/src/main/scala/chisel3/notstrict.scala b/chiselFrontend/src/main/scala/chisel3/notstrict.scala deleted file mode 100644 index bb390e7c..00000000 --- a/chiselFrontend/src/main/scala/chisel3/notstrict.scala +++ /dev/null @@ -1,16 +0,0 @@ -// See LICENSE for license details. - -package chisel3 - -import chisel3.internal.ExplicitCompileOptions - - -object NotStrict { - implicit object CompileOptions extends ExplicitCompileOptions { - val connectFieldsMustMatch = false - val declaredTypeMustBeUnbound = false - val requireIOWrap = false - val dontTryConnectionsSwapped = false - val dontAssumeDirectionality = false - } -} diff --git a/chiselFrontend/src/main/scala/chisel3/strict.scala b/chiselFrontend/src/main/scala/chisel3/strict.scala deleted file mode 100644 index 70240429..00000000 --- a/chiselFrontend/src/main/scala/chisel3/strict.scala +++ /dev/null @@ -1,16 +0,0 @@ -// See LICENSE for license details. - -package chisel3 - -import chisel3.internal.ExplicitCompileOptions - - -object Strict { - implicit object CompileOptions extends ExplicitCompileOptions { - val connectFieldsMustMatch = true - val declaredTypeMustBeUnbound = true - val requireIOWrap = true - val dontTryConnectionsSwapped = true - val dontAssumeDirectionality = true - } -} -- cgit v1.2.3 From 3442fac58a99551ca9e25dbc2c363c866c40e3cf Mon Sep 17 00:00:00 2001 From: Andrew Waterman Date: Wed, 31 Aug 2016 19:23:11 -0700 Subject: Check that Vecs have homogeneous types Vec[Element] can have heterogeneous widths. Vec[Aggregate] cannot (but possibly could relax this by stripping widths from constituent Elements and relying on width inference). --- .../src/main/scala/chisel3/core/Aggregate.scala | 17 +++++++++++++++-- chiselFrontend/src/main/scala/chisel3/core/Bits.scala | 11 ++++++++--- 2 files changed, 23 insertions(+), 5 deletions(-) (limited to 'chiselFrontend/src') diff --git a/chiselFrontend/src/main/scala/chisel3/core/Aggregate.scala b/chiselFrontend/src/main/scala/chisel3/core/Aggregate.scala index 82c6097f..e6ecff91 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/Aggregate.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/Aggregate.scala @@ -48,8 +48,21 @@ object Vec { // 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)) + def gen = elts.head match { + case e: Element => + // Vec[Element] must have homogeneous types, but may differ in width + for (elt <- elts.tail) + require(e.getClass == elt.getClass, + s"can't create Vec of heterogeneous types ${e.getClass} and ${elt.getClass}") + val maxWidth = elts.map(_.width).reduce(_ max _) + elts.head.cloneTypeWidth(maxWidth) + case a: Aggregate => + // Vec[Aggregate] must be homogeneous in type and width + for (elt <- elts.tail) + require(Mux.typesCompatible(a, elt), s"can't create Vec of heterogeneous types ${a.getClass} and ${elt.getClass}") + elts.head.cloneType + } + val vec = Wire(new Vec(gen, elts.length)) for ((v, e) <- vec zip elts) v := e vec diff --git a/chiselFrontend/src/main/scala/chisel3/core/Bits.scala b/chiselFrontend/src/main/scala/chisel3/core/Bits.scala index 015b9dfb..44beab66 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/Bits.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/Bits.scala @@ -737,10 +737,15 @@ object Mux { pushOp(DefPrim(sourceInfo, d, MultiplexOp, cond.ref, con.ref, alt.ref)) } + private[core] def typesCompatible[T <: Data](x: T, y: T): Boolean = { + val sameTypes = x.getClass == y.getClass + val sameElements = x.flatten zip y.flatten forall { case (a, b) => a.getClass == b.getClass && a.width == b.width } + val sameNumElements = x.flatten.size == y.flatten.size + sameTypes && sameElements && sameNumElements + } + 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") + require(typesCompatible(con, alt), s"can't Mux between heterogeneous types ${con.getClass} and ${alt.getClass}") doMux(cond, con, alt) } } -- cgit v1.2.3 From 4b88a5dd45337fa88178fe17324eef3661daf1b3 Mon Sep 17 00:00:00 2001 From: Jim Lawson Date: Thu, 1 Sep 2016 10:21:57 -0700 Subject: Move connection implicits from Module constructor to connection methods. Eliminate builder compileOptions. --- .../src/main/scala/chisel3/core/Aggregate.scala | 23 +++++++++++++--------- .../src/main/scala/chisel3/core/BiConnect.scala | 23 +++++++++++----------- .../src/main/scala/chisel3/core/Binding.scala | 6 +++--- .../src/main/scala/chisel3/core/Bits.scala | 1 + .../src/main/scala/chisel3/core/Data.scala | 19 +++++++++--------- .../src/main/scala/chisel3/core/Mem.scala | 1 + .../src/main/scala/chisel3/core/MonoConnect.scala | 23 ++++++++++++---------- .../src/main/scala/chisel3/core/Reg.scala | 14 ++++++------- .../src/main/scala/chisel3/internal/Builder.scala | 11 +++-------- 9 files changed, 64 insertions(+), 57 deletions(-) (limited to 'chiselFrontend/src') diff --git a/chiselFrontend/src/main/scala/chisel3/core/Aggregate.scala b/chiselFrontend/src/main/scala/chisel3/core/Aggregate.scala index 5d294ea9..c579d424 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/Aggregate.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/Aggregate.scala @@ -10,6 +10,7 @@ import chisel3.internal._ import chisel3.internal.Builder.pushCommand import chisel3.internal.firrtl._ import chisel3.internal.sourceinfo.{SourceInfo, DeprecatedSourceInfo, VecTransform, SourceInfoTransform} +import chisel3.Strict.CompileOptions /** An abstract class for data types that solely consist of (are an aggregate * of) other Data objects. @@ -51,10 +52,12 @@ object Vec { val width = elts.map(_.width).reduce(_ max _) // If an element has a direction associated with it, use the bulk connect operator. val vec = Wire(new Vec(elts.head.cloneTypeWidth(width), elts.length)) - def doConnect(sink: T, source: T) = if (elts.head.flatten.exists(_.firrtlDirection != Direction.Unspecified)) { - sink bulkConnect source - } else { - sink connect source + def doConnect(sink: T, source: T) = { + if (elts.head.flatten.exists(_.firrtlDirection != Direction.Unspecified)) { + sink bulkConnect source + } else { + sink connect source + } } for ((v, e) <- vec zip elts) { doConnect(v, e) @@ -138,27 +141,27 @@ sealed class Vec[T <: Data] private (gen: T, val length: Int) * * @note the length of this Vec must match the length of the input Seq */ - def <> (that: Seq[T])(implicit sourceInfo: SourceInfo): Unit = { + def <> (that: Seq[T])(implicit sourceInfo: SourceInfo, moduleCompileOptions: ExplicitCompileOptions): 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 bulkConnect that.asInstanceOf[Data] + def <> (that: Vec[T])(implicit sourceInfo: SourceInfo, moduleCompileOptions: ExplicitCompileOptions): Unit = this bulkConnect that.asInstanceOf[Data] /** 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 = { + def := (that: Seq[T])(implicit sourceInfo: SourceInfo, moduleCompileOptions: ExplicitCompileOptions): 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 + def := (that: Vec[T])(implicit sourceInfo: SourceInfo, moduleCompileOptions: ExplicitCompileOptions): Unit = this connect that /** Creates a dynamically indexed read or write accessor into the array. */ @@ -184,7 +187,9 @@ sealed class Vec[T <: Data] private (gen: T, val length: Int) def read(idx: UInt): T = apply(idx) @deprecated("Use Vec.apply instead", "chisel3") - def write(idx: UInt, data: T): Unit = apply(idx).:=(data)(DeprecatedSourceInfo) + def write(idx: UInt, data: T): Unit = { + apply(idx).:=(data)(DeprecatedSourceInfo, chisel3.Strict.CompileOptions) + } override def cloneType: this.type = { Vec(length, gen).asInstanceOf[this.type] diff --git a/chiselFrontend/src/main/scala/chisel3/core/BiConnect.scala b/chiselFrontend/src/main/scala/chisel3/core/BiConnect.scala index 969e5654..b0be1c38 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/BiConnect.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/BiConnect.scala @@ -2,10 +2,11 @@ package chisel3.core -import chisel3.internal.Builder.{compileOptions, pushCommand} +import chisel3.internal.Builder.pushCommand import chisel3.internal.firrtl.Connect import scala.language.experimental.macros import chisel3.internal.sourceinfo._ +import chisel3.internal.ExplicitCompileOptions /** * BiConnect.connect executes a bidirectional connection element-wise. @@ -49,11 +50,11 @@ object BiConnect { * 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 = + def connect(sourceInfo: SourceInfo, connectCompileOptions: ExplicitCompileOptions, 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) + elemConnect(sourceInfo, connectCompileOptions, left_e, right_e, context_mod) // TODO(twigg): Verify the element-level classes are connectable } // Handle Vec case @@ -61,7 +62,7 @@ object BiConnect { 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) + connect(sourceInfo, connectCompileOptions, left_v(idx), right_v(idx), context_mod) } catch { case BiConnectException(message) => throw BiConnectException(s"($idx)$message") } @@ -72,7 +73,7 @@ object BiConnect { // Verify right has no extra fields that left doesn't have for((field, right_sub) <- right_b.elements) { if(!left_b.elements.isDefinedAt(field)) { - if (compileOptions.connectFieldsMustMatch || context_mod.compileOptions.connectFieldsMustMatch) { + if (connectCompileOptions.connectFieldsMustMatch) { throw MissingLeftFieldException(field) } } @@ -81,9 +82,9 @@ object BiConnect { 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 Some(right_sub) => connect(sourceInfo, connectCompileOptions, left_sub, right_sub, context_mod) case None => { - if (compileOptions.connectFieldsMustMatch || context_mod.compileOptions.connectFieldsMustMatch) { + if (connectCompileOptions.connectFieldsMustMatch) { throw MissingRightFieldException(field) } } @@ -109,7 +110,7 @@ object BiConnect { // 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 = { + def elemConnect(implicit sourceInfo: SourceInfo, connectCompileOptions: ExplicitCompileOptions, 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 @@ -169,7 +170,7 @@ object BiConnect { case (None, Some(Input)) => issueConnectR2L(left, right) case (Some(Input), Some(Input)) => { - if (compileOptions.dontAssumeDirectionality || context_mod.compileOptions.dontAssumeDirectionality) { + if (connectCompileOptions.dontAssumeDirectionality) { throw BothDriversException } else { (left.binding, right.binding) match { @@ -181,7 +182,7 @@ object BiConnect { } } case (Some(Output), Some(Output)) => { - if (compileOptions.dontAssumeDirectionality || context_mod.compileOptions.dontAssumeDirectionality) { + if (connectCompileOptions.dontAssumeDirectionality) { throw BothDriversException } else { (left.binding, right.binding) match { @@ -193,7 +194,7 @@ object BiConnect { } } case (None, None) => { - if (compileOptions.dontAssumeDirectionality || context_mod.compileOptions.dontAssumeDirectionality) { + if (connectCompileOptions.dontAssumeDirectionality) { throw UnknownDriverException } else { issueConnectR2L(left, right) diff --git a/chiselFrontend/src/main/scala/chisel3/core/Binding.scala b/chiselFrontend/src/main/scala/chisel3/core/Binding.scala index b36794f1..5378f3ae 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/Binding.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/Binding.scala @@ -1,6 +1,6 @@ package chisel3.core -import chisel3.internal.Builder.{compileOptions, forcedModule} +import chisel3.internal.Builder.{forcedModule} /** * The purpose of a Binding is to indicate what type of hardware 'entity' a @@ -91,7 +91,7 @@ object Binding { element.binding = binder(unbound) } // If autoIOWrap is enabled and we're rebinding a PortBinding, just ignore the rebinding. - case portBound @ PortBinding(_, _) if (!(compileOptions.requireIOWrap || forcedModule.compileOptions.requireIOWrap)&& binder.isInstanceOf[PortBinder]) => + case portBound @ PortBinding(_, _) if (!(forcedModule.compileOptions.requireIOWrap) && binder.isInstanceOf[PortBinder]) => case binding => throw AlreadyBoundException(binding.toString) } ) @@ -145,7 +145,7 @@ object Binding { case binding => // The following kludge is an attempt to provide backward compatibility // It should be done at at higher level. - if ((compileOptions.requireIOWrap || forcedModule.compileOptions.requireIOWrap || !elementOfIO(element))) + if ((forcedModule.compileOptions.requireIOWrap || !elementOfIO(element))) throw NotSynthesizableException else Binding.bind(element, PortBinder(element._parent.get), "Error: IO") diff --git a/chiselFrontend/src/main/scala/chisel3/core/Bits.scala b/chiselFrontend/src/main/scala/chisel3/core/Bits.scala index c2621251..6fdec340 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/Bits.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/Bits.scala @@ -10,6 +10,7 @@ import chisel3.internal.firrtl._ import chisel3.internal.sourceinfo.{SourceInfo, DeprecatedSourceInfo, SourceInfoTransform, SourceInfoWhiteboxTransform, UIntTransform, MuxTransform} import chisel3.internal.firrtl.PrimOp._ +import chisel3.Strict.CompileOptions /** Element is a leaf data type: it cannot contain other Data objects. Example * uses are for representing primitive data types, like integers and bits. diff --git a/chiselFrontend/src/main/scala/chisel3/core/Data.scala b/chiselFrontend/src/main/scala/chisel3/core/Data.scala index ce7b58b4..bda06790 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/Data.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/Data.scala @@ -8,6 +8,7 @@ import chisel3.internal._ import chisel3.internal.Builder.pushCommand import chisel3.internal.firrtl._ import chisel3.internal.sourceinfo.{SourceInfo, DeprecatedSourceInfo, UnlocatableSourceInfo, WireTransform, SourceInfoTransform} +import chisel3.Strict.CompileOptions sealed abstract class Direction(name: String) { override def toString: String = name @@ -124,11 +125,11 @@ abstract class Data extends HasId { private[core] def badConnect(that: Data)(implicit sourceInfo: SourceInfo): Unit = throwException(s"cannot connect ${this} and ${that}") - private[chisel3] def connect(that: Data)(implicit sourceInfo: SourceInfo): Unit = { + private[chisel3] def connect(that: Data)(implicit sourceInfo: SourceInfo, connectCompileOptions: ExplicitCompileOptions): Unit = { Binding.checkSynthesizable(this, s"'this' ($this)") Binding.checkSynthesizable(that, s"'that' ($that)") try { - MonoConnect.connect(sourceInfo, this, that, Builder.forcedModule) + MonoConnect.connect(sourceInfo, connectCompileOptions, this, that, Builder.forcedModule) } catch { case MonoConnect.MonoConnectException(message) => throwException( @@ -136,11 +137,11 @@ abstract class Data extends HasId { ) } } - private[chisel3] def bulkConnect(that: Data)(implicit sourceInfo: SourceInfo): Unit = { + private[chisel3] def bulkConnect(that: Data)(implicit sourceInfo: SourceInfo, connectCompileOptions: ExplicitCompileOptions): Unit = { Binding.checkSynthesizable(this, s"'this' ($this)") Binding.checkSynthesizable(that, s"'that' ($that)") try { - BiConnect.connect(sourceInfo, this, that, Builder.forcedModule) + BiConnect.connect(sourceInfo, connectCompileOptions, this, that, Builder.forcedModule) } catch { case BiConnect.BiConnectException(message) => throwException( @@ -165,8 +166,8 @@ abstract class Data extends HasId { } clone } - final def := (that: Data)(implicit sourceInfo: SourceInfo): Unit = this connect that - final def <> (that: Data)(implicit sourceInfo: SourceInfo): Unit = this bulkConnect that + final def := (that: Data)(implicit sourceInfo: SourceInfo, connectionCompileOptions: ExplicitCompileOptions): Unit = this.connect(that)(sourceInfo, connectionCompileOptions) + final def <> (that: Data)(implicit sourceInfo: SourceInfo, connectionCompileOptions: ExplicitCompileOptions): Unit = this.bulkConnect(that)(sourceInfo, connectionCompileOptions) def litArg(): Option[LitArg] = None def litValue(): BigInt = litArg.get.num def isLit(): Boolean = litArg.isDefined @@ -254,7 +255,7 @@ object Wire { 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) + val x = Reg.makeType(chisel3.Strict.CompileOptions, t, null.asInstanceOf[T], init) // Bind each element of x to being a Wire Binding.bind(x, WireBinder(Builder.forcedModule), "Error: t") @@ -288,8 +289,8 @@ sealed class Clock extends Element(Width(1)) { private[core] def cloneTypeWidth(width: Width): this.type = cloneType private[chisel3] def toType = "Clock" - override def connect (that: Data)(implicit sourceInfo: SourceInfo): Unit = that match { - case _: Clock => super.connect(that)(sourceInfo) + override def connect (that: Data)(implicit sourceInfo: SourceInfo, connectCompileOptions: ExplicitCompileOptions): Unit = that match { + case _: Clock => super.connect(that)(sourceInfo, connectCompileOptions) case _ => super.badConnect(that)(sourceInfo) } } diff --git a/chiselFrontend/src/main/scala/chisel3/core/Mem.scala b/chiselFrontend/src/main/scala/chisel3/core/Mem.scala index 931a0489..327e119e 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/Mem.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/Mem.scala @@ -8,6 +8,7 @@ import chisel3.internal._ import chisel3.internal.Builder.pushCommand import chisel3.internal.firrtl._ import chisel3.internal.sourceinfo.{SourceInfo, DeprecatedSourceInfo, UnlocatableSourceInfo, MemTransform} +import chisel3.Strict.CompileOptions object Mem { @deprecated("Mem argument order should be size, t; this will be removed by the official release", "chisel3") diff --git a/chiselFrontend/src/main/scala/chisel3/core/MonoConnect.scala b/chiselFrontend/src/main/scala/chisel3/core/MonoConnect.scala index 41754827..1925171b 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/MonoConnect.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/MonoConnect.scala @@ -1,9 +1,12 @@ +// See LICENSE for license details. + package chisel3.core -import chisel3.internal.Builder.{compileOptions, pushCommand} +import chisel3.internal.Builder.pushCommand import chisel3.internal.firrtl.Connect import scala.language.experimental.macros import chisel3.internal.sourceinfo.{DeprecatedSourceInfo, SourceInfo, SourceInfoTransform, UnlocatableSourceInfo, WireTransform} +import chisel3.internal.ExplicitCompileOptions /** * MonoConnect.connect executes a mono-directional connection element-wise. @@ -53,11 +56,11 @@ object MonoConnect { * 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 = + def connect(sourceInfo: SourceInfo, connectCompileOptions: ExplicitCompileOptions, 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) + elemConnect(sourceInfo, connectCompileOptions, sink_e, source_e, context_mod) // TODO(twigg): Verify the element-level classes are connectable } // Handle Vec case @@ -65,7 +68,7 @@ object MonoConnect { 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) + connect(sourceInfo, connectCompileOptions, sink_v(idx), source_v(idx), context_mod) } catch { case MonoConnectException(message) => throw MonoConnectException(s"($idx)$message") } @@ -77,9 +80,9 @@ object MonoConnect { 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 Some(source_sub) => connect(sourceInfo, connectCompileOptions, sink_sub, source_sub, context_mod) case None => { - if (compileOptions.connectFieldsMustMatch || context_mod.compileOptions.connectFieldsMustMatch) { + if (connectCompileOptions.connectFieldsMustMatch) { throw MissingFieldException(field) } } @@ -100,7 +103,7 @@ object MonoConnect { // 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 = { + def elemConnect(implicit sourceInfo: SourceInfo, connectCompileOptions: ExplicitCompileOptions, 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 @@ -134,13 +137,13 @@ object MonoConnect { case (Some(Output), Some(Output)) => issueConnect(sink, source) case (Some(Output), Some(Input)) => issueConnect(sink, source) case (_, None) => { - if (!(compileOptions.dontAssumeDirectionality || context_mod.compileOptions.dontAssumeDirectionality)) { + if (!(connectCompileOptions.dontAssumeDirectionality)) { issueConnect(sink, source) } else { throw UnreadableSourceException } } - case (Some(Input), Some(Output)) if (!(compileOptions.dontTryConnectionsSwapped || context_mod.compileOptions.dontTryConnectionsSwapped)) => issueConnect(source, sink) + case (Some(Input), Some(Output)) if (!(connectCompileOptions.dontTryConnectionsSwapped)) => issueConnect(source, sink) case (Some(Input), _) => throw UnwritableSinkException } } @@ -172,7 +175,7 @@ object MonoConnect { case (Some(Input), Some(Output)) => issueConnect(sink, source) case (Some(Output), _) => throw UnwritableSinkException case (_, None) => { - if (!(compileOptions.dontAssumeDirectionality || context_mod.compileOptions.dontAssumeDirectionality)) { + if (!(connectCompileOptions.dontAssumeDirectionality)) { issueConnect(sink, source) } else { throw UnreadableSourceException diff --git a/chiselFrontend/src/main/scala/chisel3/core/Reg.scala b/chiselFrontend/src/main/scala/chisel3/core/Reg.scala index 36c88245..d147a81d 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/Reg.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/Reg.scala @@ -8,9 +8,9 @@ import chisel3.internal.firrtl._ import chisel3.internal.sourceinfo.{SourceInfo, UnlocatableSourceInfo} object Reg { - private[core] def makeType[T <: Data](t: T = null, next: T = null, init: T = null): T = { + private[core] def makeType[T <: Data](compileOptions: ExplicitCompileOptions, t: T = null, next: T = null, init: T = null): T = { if (t ne null) { - if (Builder.compileOptions.declaredTypeMustBeUnbound || Builder.forcedModule.compileOptions.declaredTypeMustBeUnbound) { + if (compileOptions.declaredTypeMustBeUnbound) { Binding.checkUnbound(t, s"t ($t) must be unbound Type. Try using cloneType?") } t.chiselCloneType @@ -40,18 +40,18 @@ object Reg { * 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 = + def apply[T <: Data](t: T = null, next: T = null, init: T = null)(implicit sourceInfo: SourceInfo, compileOptions: ExplicitCompileOptions): T = // Scala macros can't (yet) handle named or default arguments. - do_apply(t, next, init)(UnlocatableSourceInfo) + do_apply(t, next, init)(sourceInfo, compileOptions) /** 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 apply[T <: Data](outType: T)(implicit sourceInfo: SourceInfo, compileOptions: ExplicitCompileOptions): T = Reg[T](outType, null.asInstanceOf[T], null.asInstanceOf[T])(sourceInfo, compileOptions) - def do_apply[T <: Data](t: T, next: T, init: T)(implicit sourceInfo: SourceInfo): T = { + def do_apply[T <: Data](t: T, next: T, init: T)(implicit sourceInfo: SourceInfo, compileOptions: ExplicitCompileOptions = chisel3.Strict.CompileOptions): 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()). @@ -59,7 +59,7 @@ object Reg { // 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 x = makeType(compileOptions, t, next, init) val clock = Node(x._parent.get.clock) // TODO multi-clock // Bind each element of x to being a Reg diff --git a/chiselFrontend/src/main/scala/chisel3/internal/Builder.scala b/chiselFrontend/src/main/scala/chisel3/internal/Builder.scala index 0376e067..8d376810 100644 --- a/chiselFrontend/src/main/scala/chisel3/internal/Builder.scala +++ b/chiselFrontend/src/main/scala/chisel3/internal/Builder.scala @@ -129,16 +129,12 @@ private[chisel3] trait HasId extends InstanceId { } } -private[chisel3] class DynamicContext(moduleCompileOptions: Option[ExplicitCompileOptions] = None) { +private[chisel3] 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 - val compileOptions = moduleCompileOptions match { - case Some(options: ExplicitCompileOptions) => options - case None => chisel3.NotStrict.CompileOptions - } } private[chisel3] object Builder { @@ -150,7 +146,6 @@ private[chisel3] object Builder { def idGen: IdGen = dynamicContext.idGen def globalNamespace: Namespace = dynamicContext.globalNamespace def components: ArrayBuffer[Component] = dynamicContext.components - def compileOptions = dynamicContext.compileOptions def currentModule: Option[Module] = dynamicContext.currentModule def currentModule_=(target: Option[Module]): Unit = { @@ -179,8 +174,8 @@ private[chisel3] object Builder { def errors: ErrorLog = dynamicContext.errors def error(m: => String): Unit = errors.error(m) - def build[T <: Module](f: => T, moduleCompileOptions: Option[ExplicitCompileOptions] = None): Circuit = { - dynamicContextVar.withValue(Some(new DynamicContext(moduleCompileOptions))) { + def build[T <: Module](f: => T): Circuit = { + dynamicContextVar.withValue(Some(new DynamicContext())) { errors.info("Elaborating design...") val mod = f mod.forceName(mod.name, globalNamespace) -- cgit v1.2.3 From fcdc5035675e9891d6c68c97d270a25fb60b3d64 Mon Sep 17 00:00:00 2001 From: Jim Lawson Date: Thu, 1 Sep 2016 13:02:09 -0700 Subject: Deprecate Vec.fill() offering Vec(Seq.fill()). --- chiselFrontend/src/main/scala/chisel3/core/Aggregate.scala | 1 + 1 file changed, 1 insertion(+) (limited to 'chiselFrontend/src') diff --git a/chiselFrontend/src/main/scala/chisel3/core/Aggregate.scala b/chiselFrontend/src/main/scala/chisel3/core/Aggregate.scala index c579d424..ed5a8fb3 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/Aggregate.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/Aggregate.scala @@ -99,6 +99,7 @@ object Vec { * @param gen function that generates the [[Data]] that becomes the output * element */ + @deprecated("Vec.fill(n)(gen) is deprecated. Please use Vec(Seq.fill(n)(gen))", "chisel3") 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] = -- cgit v1.2.3 From ace6afb3177fbb14b8b85a16d6724ce784277f95 Mon Sep 17 00:00:00 2001 From: Andrew Waterman Date: Thu, 1 Sep 2016 20:37:06 -0700 Subject: Remove O(n^2) code in Vec.apply(Seq) The O(n) type legality check was redundantly executed n times. D'oh. --- .../src/main/scala/chisel3/core/Aggregate.scala | 26 ++++++++++------------ 1 file changed, 12 insertions(+), 14 deletions(-) (limited to 'chiselFrontend/src') diff --git a/chiselFrontend/src/main/scala/chisel3/core/Aggregate.scala b/chiselFrontend/src/main/scala/chisel3/core/Aggregate.scala index e6ecff91..f80c8d8e 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/Aggregate.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/Aggregate.scala @@ -47,22 +47,20 @@ object Vec { // 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. + + // Check that types are homogeneous. Width mismatch for Elements is safe. require(!elts.isEmpty) - def gen = elts.head match { - case e: Element => - // Vec[Element] must have homogeneous types, but may differ in width - for (elt <- elts.tail) - require(e.getClass == elt.getClass, - s"can't create Vec of heterogeneous types ${e.getClass} and ${elt.getClass}") - val maxWidth = elts.map(_.width).reduce(_ max _) - elts.head.cloneTypeWidth(maxWidth) - case a: Aggregate => - // Vec[Aggregate] must be homogeneous in type and width - for (elt <- elts.tail) - require(Mux.typesCompatible(a, elt), s"can't create Vec of heterogeneous types ${a.getClass} and ${elt.getClass}") - elts.head.cloneType + def eltsCompatible(a: Data, b: Data) = a match { + case _: Element => a.getClass == b.getClass + case _: Aggregate => Mux.typesCompatible(a, b) } - val vec = Wire(new Vec(gen, elts.length)) + + val t = elts.head + for (e <- elts.tail) + require(eltsCompatible(t, e), s"can't create Vec of heterogeneous types ${t.getClass} and ${e.getClass}") + + val maxWidth = elts.map(_.width).reduce(_ max _) + val vec = Wire(new Vec(t.cloneTypeWidth(maxWidth), elts.length)) for ((v, e) <- vec zip elts) v := e vec -- cgit v1.2.3 From 16426b3a68d85ce7dd9655b0ce773431eb69fc74 Mon Sep 17 00:00:00 2001 From: Andrew Waterman Date: Fri, 2 Sep 2016 11:14:57 -0700 Subject: Deprecate asBits; modify deprecation warnings accordingly --- chiselFrontend/src/main/scala/chisel3/core/Bits.scala | 3 ++- chiselFrontend/src/main/scala/chisel3/core/Data.scala | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) (limited to 'chiselFrontend/src') diff --git a/chiselFrontend/src/main/scala/chisel3/core/Bits.scala b/chiselFrontend/src/main/scala/chisel3/core/Bits.scala index 44beab66..57f6d8e0 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/Bits.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/Bits.scala @@ -211,6 +211,7 @@ sealed abstract class Bits(dirArg: Direction, width: Width, override val litArg: def do_asSInt(implicit sourceInfo: SourceInfo): SInt /** Reinterpret cast to Bits. */ + @deprecated("Use asUInt, which does the same thing but returns a more concrete type", "chisel3") final def asBits(): Bits = macro SourceInfoTransform.noArg def do_asBits(implicit sourceInfo: SourceInfo): Bits = asUInt() @@ -241,7 +242,7 @@ sealed abstract class Bits(dirArg: Direction, width: Width, override val litArg: 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") + @deprecated("Use asUInt, which does the same thing but makes the reinterpret cast more explicit", "chisel3") override def toBits: UInt = do_asUInt(DeprecatedSourceInfo) override def do_fromBits(that: Bits)(implicit sourceInfo: SourceInfo): this.type = { diff --git a/chiselFrontend/src/main/scala/chisel3/core/Data.scala b/chiselFrontend/src/main/scala/chisel3/core/Data.scala index 8826af51..5ae8c84d 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/Data.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/Data.scala @@ -118,7 +118,7 @@ abstract class Data(dirArg: Direction) extends HasId { * * This performs the inverse operation of fromBits(Bits). */ - @deprecated("Use asBits, which makes the reinterpret cast more explicit and actually returns Bits", "chisel3") + @deprecated("Use asUInt, which does the same thing but makes the reinterpret cast more explicit", "chisel3") def toBits(): UInt = SeqUtils.do_asUInt(this.flatten)(DeprecatedSourceInfo) /** Reinterpret cast to UInt. -- cgit v1.2.3 From 85a65019641130949fcc9082e42231a7c3618f0a Mon Sep 17 00:00:00 2001 From: Jim Lawson Date: Fri, 2 Sep 2016 14:47:29 -0700 Subject: Add/cleanup UInt/SInt factory methods. --- chiselFrontend/src/main/scala/chisel3/core/Bits.scala | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) (limited to 'chiselFrontend/src') diff --git a/chiselFrontend/src/main/scala/chisel3/core/Bits.scala b/chiselFrontend/src/main/scala/chisel3/core/Bits.scala index 6fdec340..625f985d 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/Bits.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/Bits.scala @@ -538,12 +538,16 @@ private[core] sealed trait UIntFactory { } /** Create a UInt with a specified width - compatibility with Chisel2. */ + // NOTE: This resolves UInt(width = 32) def apply(dir: Option[Direction] = None, width: Int): UInt = apply(Width(width)) /** Create a UInt literal with inferred width.- compatibility with Chisel2. */ def apply(value: BigInt): UInt = apply(value, Width()) /** Create a UInt with a specified direction and width - compatibility with Chisel2. */ - def apply(dir: Direction, width: Int): UInt = { - val result = apply(Width(width)) + def apply(dir: Direction, width: Int): UInt = apply(dir, Width(width)) + /** Create a UInt with a specified direction, but unspecified width - compatibility with Chisel2. */ + def apply(dir: Direction): UInt = apply(dir, Width()) + def apply(dir: Direction, wWidth: Width): UInt = { + val result = apply(wWidth) dir match { case Direction.Input => Input(result) case Direction.Output => Output(result) @@ -707,8 +711,11 @@ object SInt { /** Create a SInt with a specified width - compatibility with Chisel2. */ def apply(dir: Option[Direction] = None, width: Int): SInt = apply(Width(width)) /** Create a SInt with a specified direction and width - compatibility with Chisel2. */ - def apply(dir: Direction, width: Int): SInt = { - val result = apply(Width(width)) + def apply(dir: Direction, width: Int): SInt = apply(dir, Width(width)) + /** Create a SInt with a specified direction, but unspecified width - compatibility with Chisel2. */ + def apply(dir: Direction): SInt = apply(dir, Width()) + def apply(dir: Direction, wWidth: Width): SInt = { + val result = apply(wWidth) dir match { case Direction.Input => Input(result) case Direction.Output => Output(result) -- cgit v1.2.3 From 0ed5eb48cdb916b644aaf9e5dbf48f6cfb6c60f4 Mon Sep 17 00:00:00 2001 From: Jack Koenig Date: Wed, 7 Sep 2016 14:18:29 -0700 Subject: Add Printable (#270) Printable is a new type that changes how printing of Chisel types is represented It uses an ordered collection rather than a format string and specifiers Features: - Custom String Interpolator for Scala-like printf - String-like manipulation of "hardware strings" for custom pretty-printing - Default pretty-printing for Chisel data types--- .../src/main/scala/chisel3/core/Aggregate.scala | 26 ++++ .../src/main/scala/chisel3/core/Bits.scala | 3 + .../src/main/scala/chisel3/core/Data.scala | 6 + .../src/main/scala/chisel3/core/Printable.scala | 150 +++++++++++++++++++++ .../src/main/scala/chisel3/core/Printf.scala | 44 +++++- .../main/scala/chisel3/internal/firrtl/IR.scala | 18 +-- 6 files changed, 225 insertions(+), 22 deletions(-) create mode 100644 chiselFrontend/src/main/scala/chisel3/core/Printable.scala (limited to 'chiselFrontend/src') diff --git a/chiselFrontend/src/main/scala/chisel3/core/Aggregate.scala b/chiselFrontend/src/main/scala/chisel3/core/Aggregate.scala index f80c8d8e..d07c5dcd 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/Aggregate.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/Aggregate.scala @@ -180,6 +180,17 @@ sealed class Vec[T <: Data] private (gen: => T, val length: Int) for ((elt, i) <- self zipWithIndex) elt.setRef(this, i) + + /** Default "pretty-print" implementation + * Analogous to printing a Seq + * Results in "Vec(elt0, elt1, ...)" + */ + def toPrintable: Printable = { + val elts = + if (length == 0) List.empty[Printable] + else self flatMap (e => List(e.toPrintable, PString(", "))) dropRight 1 + PString("Vec(") + Printables(elts) + PString(")") + } } /** A trait for [[Vec]]s containing common hardware generators for collection @@ -381,6 +392,21 @@ class Bundle extends Aggregate(NO_DIR) { this } } + + /** Default "pretty-print" implementation + * Analogous to printing a Map + * Results in "Bundle(elt0.name -> elt0.value, ...)" + */ + def toPrintable: Printable = { + val elts = + if (elements.isEmpty) List.empty[Printable] + else { + elements.toList.reverse flatMap { case (name, data) => + List(PString(s"$name -> "), data.toPrintable, PString(", ")) + } dropRight 1 // Remove trailing ", " + } + PString("Bundle(") + Printables(elts) + PString(")") + } } private[core] object Bundle { diff --git a/chiselFrontend/src/main/scala/chisel3/core/Bits.scala b/chiselFrontend/src/main/scala/chisel3/core/Bits.scala index 57f6d8e0..77a31252 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/Bits.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/Bits.scala @@ -250,6 +250,9 @@ sealed abstract class Bits(dirArg: Direction, width: Width, override val litArg: res := that res } + + /** Default print as [[Decimal]] */ + final def toPrintable: Printable = Decimal(this) } /** Provides a set of operations to create UInt types and literals. diff --git a/chiselFrontend/src/main/scala/chisel3/core/Data.scala b/chiselFrontend/src/main/scala/chisel3/core/Data.scala index 5ae8c84d..573632ab 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/Data.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/Data.scala @@ -132,6 +132,9 @@ abstract class Data(dirArg: Direction) extends HasId { def do_asUInt(implicit sourceInfo: SourceInfo): UInt = SeqUtils.do_asUInt(this.flatten)(sourceInfo) + + /** Default pretty printing */ + def toPrintable: Printable } object Wire { @@ -171,4 +174,7 @@ sealed class Clock(dirArg: Direction) extends Element(dirArg, Width(1)) { case _: Clock => this connect that case _ => this badConnect that } + + /** Not really supported */ + def toPrintable: Printable = PString("CLOCK") } diff --git a/chiselFrontend/src/main/scala/chisel3/core/Printable.scala b/chiselFrontend/src/main/scala/chisel3/core/Printable.scala new file mode 100644 index 00000000..13d5d74e --- /dev/null +++ b/chiselFrontend/src/main/scala/chisel3/core/Printable.scala @@ -0,0 +1,150 @@ +// See LICENSE for license details. + +package chisel3.core + +import chisel3.internal.firrtl.Component +import chisel3.internal.HasId + +import scala.collection.mutable + +import java.util.{ + MissingFormatArgumentException, + UnknownFormatConversionException +} + +/** Superclass of things that can be printed in the resulting circuit + * + * Usually created using the custom string interpolator p"..." + * TODO Should we provide more functions like map and mkPrintable? + */ +sealed abstract class Printable { + /** Unpack into format String and a List of String arguments (identifiers) + * @note This must be called after elaboration when Chisel nodes actually + * have names + */ + def unpack: (String, Iterable[String]) + /** Allow for appending Printables like Strings */ + final def +(that: Printable) = Printables(List(this, that)) + /** Allow for appending Strings to Printables */ + final def +(that: String) = Printables(List(this, PString(that))) +} +object Printable { + /** Pack standard printf fmt, args* style into Printable + */ + def pack(fmt: String, data: Data*): Printable = { + val args = data.toIterator + + // Error handling + def carrotAt(index: Int) = (" " * index) + "^" + def errorMsg(index: Int) = + s"""| fmt = "$fmt" + | ${carrotAt(index)} + | data = ${data mkString ", "}""".stripMargin + def getArg(i: Int): Data = { + if (!args.hasNext) { + val msg = "has no matching argument!\n" + errorMsg(i) + // Exception wraps msg in s"Format Specifier '$msg'" + throw new MissingFormatArgumentException(msg) + } + args.next() + } + + val pables = mutable.ListBuffer.empty[Printable] + var str = "" + var percent = false + for ((c, i) <- fmt.zipWithIndex) { + if (percent) { + val arg = c match { + case FirrtlFormat(x) => FirrtlFormat(x.toString, getArg(i)) + case 'n' => Name(getArg(i)) + case 'N' => FullName(getArg(i)) + case '%' => Percent + case x => + val msg = s"Illegal format specifier '$x'!\n" + errorMsg(i) + throw new UnknownFormatConversionException(msg) + } + pables += PString(str dropRight 1) // remove format % + pables += arg + str = "" + percent = false + } else { + str += c + percent = c == '%' + } + } + if (percent) { + val msg = s"Trailing %\n" + errorMsg(fmt.size - 1) + throw new UnknownFormatConversionException(msg) + } + require(!args.hasNext, + s"Too many arguments! More format specifier(s) expected!\n" + + errorMsg(fmt.size)) + + pables += PString(str) + Printables(pables) + } +} + +case class Printables(pables: Iterable[Printable]) extends Printable { + require(pables.hasDefiniteSize, "Infinite-sized iterables are not supported!") + final def unpack: (String, Iterable[String]) = { + val (fmts, args) = pables.map(_.unpack).unzip + (fmts.mkString, args.flatten) + } +} +/** Wrapper for printing Scala Strings */ +case class PString(str: String) extends Printable { + final def unpack: (String, Iterable[String]) = + (str replaceAll ("%", "%%"), List.empty) +} +/** Superclass for Firrtl format specifiers for Bits */ +sealed abstract class FirrtlFormat(specifier: Char) extends Printable { + def bits: Bits + def unpack: (String, Iterable[String]) = { + val id = if (bits.isLit) bits.ref.name else bits.instanceName + (s"%$specifier", List(id)) + } +} +object FirrtlFormat { + final val legalSpecifiers = List('d', 'x', 'b', 'c') + + def unapply(x: Char): Option[Char] = + Option(x) filter (x => legalSpecifiers contains x) + + /** Helper for constructing Firrtl Formats + * Accepts data to simplify pack + */ + def apply(specifier: String, data: Data): FirrtlFormat = { + val bits = data match { + case b: Bits => b + case d => throw new Exception(s"Trying to construct FirrtlFormat with non-bits $d!") + } + specifier match { + case "d" => Decimal(bits) + case "x" => Hexadecimal(bits) + case "b" => Binary(bits) + case "c" => Character(bits) + case c => throw new Exception(s"Illegal format specifier '$c'!") + } + } +} +/** Format bits as Decimal */ +case class Decimal(bits: Bits) extends FirrtlFormat('d') +/** Format bits as Hexidecimal */ +case class Hexadecimal(bits: Bits) extends FirrtlFormat('x') +/** Format bits as Binary */ +case class Binary(bits: Bits) extends FirrtlFormat('b') +/** Format bits as Character */ +case class Character(bits: Bits) extends FirrtlFormat('c') +/** Put innermost name (eg. field of bundle) */ +case class Name(data: Data) extends Printable { + final def unpack: (String, Iterable[String]) = (data.ref.name, List.empty) +} +/** Put full name within parent namespace (eg. bundleName.field) */ +case class FullName(hasId: HasId) extends Printable { + final def unpack: (String, Iterable[String]) = (hasId.instanceName, List.empty) +} +/** Represents escaped percents */ +case object Percent extends Printable { + final def unpack: (String, Iterable[String]) = ("%%", List.empty) +} diff --git a/chiselFrontend/src/main/scala/chisel3/core/Printf.scala b/chiselFrontend/src/main/scala/chisel3/core/Printf.scala index b0a3c955..55197425 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/Printf.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/Printf.scala @@ -10,6 +10,24 @@ import chisel3.internal.firrtl._ import chisel3.internal.sourceinfo.SourceInfo object printf { // scalastyle:ignore object.name + /** Helper for packing escape characters */ + private[chisel3] def format(formatIn: String): String = { + require(formatIn forall (c => c.toInt > 0 && c.toInt < 128), + "format strings must comprise non-null ASCII values") + 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 "" + } + /** Prints a message in simulation. * * Does not fire when in reset (defined as the encapsulating Module's @@ -23,14 +41,30 @@ object printf { // scalastyle:ignore object.name * @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:_*) + def apply(fmt: String, data: Bits*)(implicit sourceInfo: SourceInfo): Unit = + apply(Printable.pack(fmt, data:_*)) + /** 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 pable [[Printable]] to print + */ + def apply(pable: Printable)(implicit sourceInfo: SourceInfo): Unit = { + when (!Builder.dynamicContext.currentModule.get.reset) { + printfWithoutReset(pable) } } - private[core] def printfWithoutReset(fmt: String, data: Bits*)(implicit sourceInfo: SourceInfo) { + private[chisel3] def printfWithoutReset(pable: Printable)(implicit sourceInfo: SourceInfo): Unit = { val clock = Builder.dynamicContext.currentModule.get.clock - pushCommand(Printf(sourceInfo, Node(clock), fmt, data.map((d: Bits) => d.ref))) + pushCommand(Printf(sourceInfo, Node(clock), pable)) } + private[chisel3] def printfWithoutReset(fmt: String, data: Bits*)(implicit sourceInfo: SourceInfo): Unit = + printfWithoutReset(Printable.pack(fmt, data:_*)) } diff --git a/chiselFrontend/src/main/scala/chisel3/internal/firrtl/IR.scala b/chiselFrontend/src/main/scala/chisel3/internal/firrtl/IR.scala index 64d7d5fd..1f05b6e2 100644 --- a/chiselFrontend/src/main/scala/chisel3/internal/firrtl/IR.scala +++ b/chiselFrontend/src/main/scala/chisel3/internal/firrtl/IR.scala @@ -169,22 +169,6 @@ case class ConnectInit(sourceInfo: SourceInfo, loc: Node, exp: Arg) extends Comm 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 Printf(sourceInfo: SourceInfo, clk: Arg, pable: Printable) extends Command case class Circuit(name: String, components: Seq[Component]) -- cgit v1.2.3 From f793453ba6c4c42ef61eda3af8f04f7cadf80b95 Mon Sep 17 00:00:00 2001 From: jackkoenig Date: Wed, 7 Sep 2016 17:51:30 -0700 Subject: Fix bug in Printable FullName of submodule port Printable was using HasId.instanceName to get full names of Chisel nodes. instanceName uses the parent module of the HasId to get the Component to use in calling fullName on the underlying Ref. Unfortunately this means that any reference to a port of a instance will leave off the instance name. Fixing this required the following: - Add Component argument to Printable.unpack so that we can call Arg.fullName directly in the Printable - Pass the currently emitting module as the Component to Printable.unpack in the Emitter - Remove ability to create FullName Printables from Modules since the Module name is not known until after the printf is already emitted This commit also updates the PrintableSpec test to check that FullName and Decimal printing work on ports of instances --- .../src/main/scala/chisel3/core/Printable.scala | 24 ++++++++++++---------- 1 file changed, 13 insertions(+), 11 deletions(-) (limited to 'chiselFrontend/src') diff --git a/chiselFrontend/src/main/scala/chisel3/core/Printable.scala b/chiselFrontend/src/main/scala/chisel3/core/Printable.scala index 13d5d74e..f6e63936 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/Printable.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/Printable.scala @@ -15,6 +15,9 @@ import java.util.{ /** Superclass of things that can be printed in the resulting circuit * * Usually created using the custom string interpolator p"..." + * TODO Add support for names of Modules + * Currently impossible because unpack is called before the name is selected + * Could be implemented by adding a new format specifier to Firrtl (eg. %m) * TODO Should we provide more functions like map and mkPrintable? */ sealed abstract class Printable { @@ -22,7 +25,7 @@ sealed abstract class Printable { * @note This must be called after elaboration when Chisel nodes actually * have names */ - def unpack: (String, Iterable[String]) + def unpack(ctx: Component): (String, Iterable[String]) /** Allow for appending Printables like Strings */ final def +(that: Printable) = Printables(List(this, that)) /** Allow for appending Strings to Printables */ @@ -87,22 +90,21 @@ object Printable { case class Printables(pables: Iterable[Printable]) extends Printable { require(pables.hasDefiniteSize, "Infinite-sized iterables are not supported!") - final def unpack: (String, Iterable[String]) = { - val (fmts, args) = pables.map(_.unpack).unzip + final def unpack(ctx: Component): (String, Iterable[String]) = { + val (fmts, args) = pables.map(_ unpack ctx).unzip (fmts.mkString, args.flatten) } } /** Wrapper for printing Scala Strings */ case class PString(str: String) extends Printable { - final def unpack: (String, Iterable[String]) = + final def unpack(ctx: Component): (String, Iterable[String]) = (str replaceAll ("%", "%%"), List.empty) } /** Superclass for Firrtl format specifiers for Bits */ sealed abstract class FirrtlFormat(specifier: Char) extends Printable { def bits: Bits - def unpack: (String, Iterable[String]) = { - val id = if (bits.isLit) bits.ref.name else bits.instanceName - (s"%$specifier", List(id)) + def unpack(ctx: Component): (String, Iterable[String]) = { + (s"%$specifier", List(bits.ref.fullName(ctx))) } } object FirrtlFormat { @@ -138,13 +140,13 @@ case class Binary(bits: Bits) extends FirrtlFormat('b') case class Character(bits: Bits) extends FirrtlFormat('c') /** Put innermost name (eg. field of bundle) */ case class Name(data: Data) extends Printable { - final def unpack: (String, Iterable[String]) = (data.ref.name, List.empty) + final def unpack(ctx: Component): (String, Iterable[String]) = (data.ref.name, List.empty) } /** Put full name within parent namespace (eg. bundleName.field) */ -case class FullName(hasId: HasId) extends Printable { - final def unpack: (String, Iterable[String]) = (hasId.instanceName, List.empty) +case class FullName(data: Data) extends Printable { + final def unpack(ctx: Component): (String, Iterable[String]) = (data.ref.fullName(ctx), List.empty) } /** Represents escaped percents */ case object Percent extends Printable { - final def unpack: (String, Iterable[String]) = ("%%", List.empty) + final def unpack(ctx: Component): (String, Iterable[String]) = ("%%", List.empty) } -- cgit v1.2.3 From 19f5b7c6841bda318288990e643eb02fa22a49e2 Mon Sep 17 00:00:00 2001 From: Jim Lawson Date: Fri, 9 Sep 2016 17:23:14 -0700 Subject: Convert to NotStrict for internal connection checks. --- chiselFrontend/src/main/scala/chisel3/core/Aggregate.scala | 4 ++-- chiselFrontend/src/main/scala/chisel3/core/Bits.scala | 2 +- chiselFrontend/src/main/scala/chisel3/core/Data.scala | 4 ++-- chiselFrontend/src/main/scala/chisel3/core/Mem.scala | 2 +- chiselFrontend/src/main/scala/chisel3/core/Reg.scala | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) (limited to 'chiselFrontend/src') diff --git a/chiselFrontend/src/main/scala/chisel3/core/Aggregate.scala b/chiselFrontend/src/main/scala/chisel3/core/Aggregate.scala index ed5a8fb3..596a7244 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/Aggregate.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/Aggregate.scala @@ -10,7 +10,7 @@ import chisel3.internal._ import chisel3.internal.Builder.pushCommand import chisel3.internal.firrtl._ import chisel3.internal.sourceinfo.{SourceInfo, DeprecatedSourceInfo, VecTransform, SourceInfoTransform} -import chisel3.Strict.CompileOptions +import chisel3.NotStrict.CompileOptions /** An abstract class for data types that solely consist of (are an aggregate * of) other Data objects. @@ -189,7 +189,7 @@ sealed class Vec[T <: Data] private (gen: T, val length: Int) @deprecated("Use Vec.apply instead", "chisel3") def write(idx: UInt, data: T): Unit = { - apply(idx).:=(data)(DeprecatedSourceInfo, chisel3.Strict.CompileOptions) + apply(idx).:=(data)(DeprecatedSourceInfo, chisel3.NotStrict.CompileOptions) } override def cloneType: this.type = { diff --git a/chiselFrontend/src/main/scala/chisel3/core/Bits.scala b/chiselFrontend/src/main/scala/chisel3/core/Bits.scala index 625f985d..8a8721f9 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/Bits.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/Bits.scala @@ -10,7 +10,7 @@ import chisel3.internal.firrtl._ import chisel3.internal.sourceinfo.{SourceInfo, DeprecatedSourceInfo, SourceInfoTransform, SourceInfoWhiteboxTransform, UIntTransform, MuxTransform} import chisel3.internal.firrtl.PrimOp._ -import chisel3.Strict.CompileOptions +import chisel3.NotStrict.CompileOptions /** Element is a leaf data type: it cannot contain other Data objects. Example * uses are for representing primitive data types, like integers and bits. diff --git a/chiselFrontend/src/main/scala/chisel3/core/Data.scala b/chiselFrontend/src/main/scala/chisel3/core/Data.scala index bda06790..991b1898 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/Data.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/Data.scala @@ -8,7 +8,7 @@ import chisel3.internal._ import chisel3.internal.Builder.pushCommand import chisel3.internal.firrtl._ import chisel3.internal.sourceinfo.{SourceInfo, DeprecatedSourceInfo, UnlocatableSourceInfo, WireTransform, SourceInfoTransform} -import chisel3.Strict.CompileOptions +import chisel3.NotStrict.CompileOptions sealed abstract class Direction(name: String) { override def toString: String = name @@ -255,7 +255,7 @@ object Wire { do_apply(t, init)(UnlocatableSourceInfo) def do_apply[T <: Data](t: T, init: T)(implicit sourceInfo: SourceInfo): T = { - val x = Reg.makeType(chisel3.Strict.CompileOptions, t, null.asInstanceOf[T], init) + val x = Reg.makeType(chisel3.NotStrict.CompileOptions, t, null.asInstanceOf[T], init) // Bind each element of x to being a Wire Binding.bind(x, WireBinder(Builder.forcedModule), "Error: t") diff --git a/chiselFrontend/src/main/scala/chisel3/core/Mem.scala b/chiselFrontend/src/main/scala/chisel3/core/Mem.scala index 327e119e..5eaaf262 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/Mem.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/Mem.scala @@ -8,7 +8,7 @@ import chisel3.internal._ import chisel3.internal.Builder.pushCommand import chisel3.internal.firrtl._ import chisel3.internal.sourceinfo.{SourceInfo, DeprecatedSourceInfo, UnlocatableSourceInfo, MemTransform} -import chisel3.Strict.CompileOptions +import chisel3.NotStrict.CompileOptions object Mem { @deprecated("Mem argument order should be size, t; this will be removed by the official release", "chisel3") diff --git a/chiselFrontend/src/main/scala/chisel3/core/Reg.scala b/chiselFrontend/src/main/scala/chisel3/core/Reg.scala index d147a81d..2569e9ea 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/Reg.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/Reg.scala @@ -51,7 +51,7 @@ object Reg { */ def apply[T <: Data](outType: T)(implicit sourceInfo: SourceInfo, compileOptions: ExplicitCompileOptions): T = Reg[T](outType, null.asInstanceOf[T], null.asInstanceOf[T])(sourceInfo, compileOptions) - def do_apply[T <: Data](t: T, next: T, init: T)(implicit sourceInfo: SourceInfo, compileOptions: ExplicitCompileOptions = chisel3.Strict.CompileOptions): T = { + def do_apply[T <: Data](t: T, next: T, init: T)(implicit sourceInfo: SourceInfo, compileOptions: ExplicitCompileOptions = chisel3.NotStrict.CompileOptions): 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()). -- cgit v1.2.3 From 920f6dc168d8e486733666368c7e363065b685ee Mon Sep 17 00:00:00 2001 From: Jim Lawson Date: Fri, 2 Sep 2016 12:53:08 -0700 Subject: Add direction-only (no width) UInt factory method. --- chiselFrontend/src/main/scala/chisel3/core/Bits.scala | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'chiselFrontend/src') diff --git a/chiselFrontend/src/main/scala/chisel3/core/Bits.scala b/chiselFrontend/src/main/scala/chisel3/core/Bits.scala index 8b3723f5..611a49be 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/Bits.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/Bits.scala @@ -558,6 +558,15 @@ private[core] sealed trait UIntFactory { case Direction.Unspecified => result } } + /** Create a UInt with a specified direction, but unspecified width - compatibility with Chisel2. */ + def apply(dir: Direction): UInt = { + val result = apply(Width()) + dir match { + case Direction.Input => Input(result) + case Direction.Output => Output(result) + case Direction.Unspecified => result + } + } private def parse(n: String) = { val (base, num) = n.splitAt(1) -- cgit v1.2.3 From 64e4df3d92727d83d5d627114d7002b97f901052 Mon Sep 17 00:00:00 2001 From: Jim Lawson Date: Thu, 15 Sep 2016 14:36:29 -0700 Subject: Revert "Add direction-only (no width) UInt factory method." This reverts commit 920f6dc168d8e486733666368c7e363065b685ee. --- chiselFrontend/src/main/scala/chisel3/core/Bits.scala | 9 --------- 1 file changed, 9 deletions(-) (limited to 'chiselFrontend/src') diff --git a/chiselFrontend/src/main/scala/chisel3/core/Bits.scala b/chiselFrontend/src/main/scala/chisel3/core/Bits.scala index 611a49be..8b3723f5 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/Bits.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/Bits.scala @@ -558,15 +558,6 @@ private[core] sealed trait UIntFactory { case Direction.Unspecified => result } } - /** Create a UInt with a specified direction, but unspecified width - compatibility with Chisel2. */ - def apply(dir: Direction): UInt = { - val result = apply(Width()) - dir match { - case Direction.Input => Input(result) - case Direction.Output => Output(result) - case Direction.Unspecified => result - } - } private def parse(n: String) = { val (base, num) = n.splitAt(1) -- cgit v1.2.3 From 53721ff4fd53f27edd75de8eb649a2e20390cceb Mon Sep 17 00:00:00 2001 From: Jim Lawson Date: Thu, 15 Sep 2016 15:43:52 -0700 Subject: add optional directionality assumption to BiConnect.elemConnect --- chiselFrontend/src/main/scala/chisel3/core/BiConnect.scala | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) (limited to 'chiselFrontend/src') diff --git a/chiselFrontend/src/main/scala/chisel3/core/BiConnect.scala b/chiselFrontend/src/main/scala/chisel3/core/BiConnect.scala index b0be1c38..ce70a19a 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/BiConnect.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/BiConnect.scala @@ -217,8 +217,18 @@ object BiConnect { case (Some(Input), Some(Input)) => throw NeitherDriverException case (Some(Output), Some(Output)) => throw BothDriversException - case (_, None) => throw UnknownRelationException - case (None, _) => throw UnknownRelationException + case (_, None) => + if (connectCompileOptions.dontAssumeDirectionality) { + throw UnknownRelationException + } else { + issueConnectR2L(left, right) + } + case (None, _) => + if (connectCompileOptions.dontAssumeDirectionality) { + throw UnknownRelationException + } else { + issueConnectR2L(left, right) + } } } -- cgit v1.2.3 From a2cb95bfe9e9c30b73284e97048fa0187ab0ee1d Mon Sep 17 00:00:00 2001 From: Andrew Waterman Date: Wed, 21 Sep 2016 12:44:36 -0700 Subject: Make implicit clock name consistent (#288) In the Chisel frontend, the implicit clock is named clock, but in the generated FIRRTL, it is named clk. There is no reason for this discrepancy, and yet fixing it is painful, as it will break test harnesses. Better to take the pain now than later. Resolves #258.--- chiselFrontend/src/main/scala/chisel3/core/Module.scala | 2 +- chiselFrontend/src/main/scala/chisel3/internal/firrtl/IR.scala | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'chiselFrontend/src') diff --git a/chiselFrontend/src/main/scala/chisel3/core/Module.scala b/chiselFrontend/src/main/scala/chisel3/core/Module.scala index 2426ae78..8093babc 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/Module.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/Module.scala @@ -94,7 +94,7 @@ extends HasId { private[chisel3] def addId(d: HasId) { _ids += d } private[core] def ports: Seq[(String,Data)] = Vector( - ("clk", clock), ("reset", reset), ("io", io) + ("clock", clock), ("reset", reset), ("io", io) ) private[core] def computePorts = for((name, port) <- ports) yield { diff --git a/chiselFrontend/src/main/scala/chisel3/internal/firrtl/IR.scala b/chiselFrontend/src/main/scala/chisel3/internal/firrtl/IR.scala index 1f05b6e2..e39b007e 100644 --- a/chiselFrontend/src/main/scala/chisel3/internal/firrtl/IR.scala +++ b/chiselFrontend/src/main/scala/chisel3/internal/firrtl/IR.scala @@ -166,9 +166,9 @@ 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 Stop(sourceInfo: SourceInfo, clock: 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, pable: Printable) extends Command +case class Printf(sourceInfo: SourceInfo, clock: Arg, pable: Printable) extends Command case class Circuit(name: String, components: Seq[Component]) -- cgit v1.2.3 From b18e98ba2d058c7dd24f96f005486b70c856aeca Mon Sep 17 00:00:00 2001 From: Andrew Waterman Date: Wed, 21 Sep 2016 16:16:25 -0700 Subject: Expose FIRRTL asClock construct Additionally, fix Clock.asUInt (previously, it threw an esoteric exception), and add a simple test of both.--- chiselFrontend/src/main/scala/chisel3/core/Bits.scala | 5 +++++ chiselFrontend/src/main/scala/chisel3/core/Data.scala | 5 ++++- chiselFrontend/src/main/scala/chisel3/internal/firrtl/IR.scala | 1 + 3 files changed, 10 insertions(+), 1 deletion(-) (limited to 'chiselFrontend/src') diff --git a/chiselFrontend/src/main/scala/chisel3/core/Bits.scala b/chiselFrontend/src/main/scala/chisel3/core/Bits.scala index 77a31252..d7464efa 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/Bits.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/Bits.scala @@ -699,6 +699,11 @@ sealed class Bool(dir: Direction, lit: Option[ULit] = None) extends UInt(dir, Wi def && (that: Bool): Bool = macro SourceInfoTransform.thatArg def do_&& (that: Bool)(implicit sourceInfo: SourceInfo): Bool = this & that + + /** Reinterprets this Bool as a Clock. */ + def asClock(): Clock = macro SourceInfoTransform.noArg + + def do_asClock(implicit sourceInfo: SourceInfo): Clock = pushOp(DefPrim(sourceInfo, Clock(), AsClockOp, ref)) } object Bool { diff --git a/chiselFrontend/src/main/scala/chisel3/core/Data.scala b/chiselFrontend/src/main/scala/chisel3/core/Data.scala index 573632ab..197b6181 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/Data.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/Data.scala @@ -5,9 +5,10 @@ package chisel3.core import scala.language.experimental.macros import chisel3.internal._ -import chisel3.internal.Builder.pushCommand +import chisel3.internal.Builder.{pushCommand, pushOp} import chisel3.internal.firrtl._ import chisel3.internal.sourceinfo.{SourceInfo, DeprecatedSourceInfo, UnlocatableSourceInfo, WireTransform, SourceInfoTransform} +import chisel3.internal.firrtl.PrimOp.AsUIntOp sealed abstract class Direction(name: String) { override def toString: String = name @@ -177,4 +178,6 @@ sealed class Clock(dirArg: Direction) extends Element(dirArg, Width(1)) { /** Not really supported */ def toPrintable: Printable = PString("CLOCK") + + override def do_asUInt(implicit sourceInfo: SourceInfo): UInt = pushOp(DefPrim(sourceInfo, UInt(this.width), AsUIntOp, ref)) } diff --git a/chiselFrontend/src/main/scala/chisel3/internal/firrtl/IR.scala b/chiselFrontend/src/main/scala/chisel3/internal/firrtl/IR.scala index e39b007e..0641686c 100644 --- a/chiselFrontend/src/main/scala/chisel3/internal/firrtl/IR.scala +++ b/chiselFrontend/src/main/scala/chisel3/internal/firrtl/IR.scala @@ -42,6 +42,7 @@ object PrimOp { val ConvertOp = PrimOp("cvt") val AsUIntOp = PrimOp("asUInt") val AsSIntOp = PrimOp("asSInt") + val AsClockOp = PrimOp("asClock") } abstract class Arg { -- cgit v1.2.3 From 6eb00023fcc3ad77b98e51971f6e193ea506b9cc Mon Sep 17 00:00:00 2001 From: ducky Date: Wed, 21 Sep 2016 17:59:38 -0700 Subject: Improved scaladoc in utils and friends --- .../src/main/scala/chisel3/core/SeqUtils.scala | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) (limited to 'chiselFrontend/src') diff --git a/chiselFrontend/src/main/scala/chisel3/core/SeqUtils.scala b/chiselFrontend/src/main/scala/chisel3/core/SeqUtils.scala index 63bcc87f..0d8604cd 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/SeqUtils.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/SeqUtils.scala @@ -7,7 +7,12 @@ import scala.language.experimental.macros import chisel3.internal.sourceinfo.{SourceInfo, SourceInfoTransform} private[chisel3] object SeqUtils { - /** Equivalent to Cat(r(n-1), ..., r(0)) */ + /** Concatenates the data elements of the input sequence, in sequence order, together. + * The first element of the sequence forms the least significant bits, while the last element + * in the sequence forms the most significant bits. + * + * Equivalent to r(n-1) ## ... ## r(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 = { @@ -20,7 +25,8 @@ private[chisel3] object SeqUtils { } } - /** Counts the number of true Bools in a Seq */ + /** Outputs the number of elements that === Bool(true). + */ def count(in: Seq[Bool]): UInt = macro SourceInfoTransform.inArg def do_count(in: Seq[Bool])(implicit sourceInfo: SourceInfo): UInt = in.size match { @@ -29,7 +35,8 @@ private[chisel3] object SeqUtils { case n => count(in take n/2) +& count(in drop n/2) } - /** Returns data value corresponding to first true predicate */ + /** Returns the data value corresponding to the 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 = { @@ -40,7 +47,10 @@ private[chisel3] object SeqUtils { } } - /** Returns data value corresponding to lone true predicate */ + /** Returns the data value corresponding to the lone true predicate. + * + * @note assumes exactly one true predicate, results undefined otherwise + */ 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 = { -- cgit v1.2.3 From bd9276f4f78c712e98b658ad9e0df81abf94c57b Mon Sep 17 00:00:00 2001 From: ducky Date: Mon, 26 Sep 2016 14:12:05 -0700 Subject: Add Strict default for compile options --- .../src/main/scala/chisel3/internal/CompileOptions.scala | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'chiselFrontend/src') diff --git a/chiselFrontend/src/main/scala/chisel3/internal/CompileOptions.scala b/chiselFrontend/src/main/scala/chisel3/internal/CompileOptions.scala index 2890f6dc..2b913908 100644 --- a/chiselFrontend/src/main/scala/chisel3/internal/CompileOptions.scala +++ b/chiselFrontend/src/main/scala/chisel3/internal/CompileOptions.scala @@ -2,6 +2,9 @@ package chisel3.internal +import scala.language.experimental.macros +import scala.reflect.macros.blackbox.Context + trait CompileOptions { // Should Bundle connections require a strict match of fields. // If true and the same fields aren't present in both source and sink, a MissingFieldException, @@ -15,6 +18,11 @@ trait CompileOptions { trait ExplicitCompileOptions extends CompileOptions +object ExplicitCompileOptions { + // Provides a low priority Strict default. Can be overridden by importing the NotStrict option. + implicit def materialize: ExplicitCompileOptions = chisel3.Strict.CompileOptions +} + ///** Initialize compilation options from a string map. // * // * @param optionsMap the map from "option" to "value" -- cgit v1.2.3 From 2edfe895e4ff9f751c52904f73fe701502aa926a Mon Sep 17 00:00:00 2001 From: Jim Lawson Date: Wed, 28 Sep 2016 08:43:59 -0700 Subject: Don't use firrtlDirection for direction checks - fix #298. firrtlDirection should only be used for emitting firrtl. Any checks on the actual direction should use the bound Direction `dir`. --- chiselFrontend/src/main/scala/chisel3/core/Aggregate.scala | 2 +- chiselFrontend/src/main/scala/chisel3/core/Data.scala | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) (limited to 'chiselFrontend/src') diff --git a/chiselFrontend/src/main/scala/chisel3/core/Aggregate.scala b/chiselFrontend/src/main/scala/chisel3/core/Aggregate.scala index 6baf5202..a0eefbfe 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/Aggregate.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/Aggregate.scala @@ -63,7 +63,7 @@ object Vec { val maxWidth = elts.map(_.width).reduce(_ max _) val vec = Wire(new Vec(t.cloneTypeWidth(maxWidth), elts.length)) def doConnect(sink: T, source: T) = { - if (elts.head.flatten.exists(_.firrtlDirection != Direction.Unspecified)) { + if (elts.head.flatten.exists(_.dir != Direction.Unspecified)) { sink bulkConnect source } else { sink connect source diff --git a/chiselFrontend/src/main/scala/chisel3/core/Data.scala b/chiselFrontend/src/main/scala/chisel3/core/Data.scala index 4bb58572..52bc8128 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/Data.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/Data.scala @@ -241,7 +241,9 @@ abstract class Data extends HasId { // firrtlDirection is the direction we report to firrtl. // It maintains the user-specified value (as opposed to the "actual" or applied/propagated value). - var firrtlDirection: Direction = Direction.Unspecified + // NOTE: This should only be used for emitting acceptable firrtl. + // The Element.dir should be used for any tests involving direction. + private var firrtlDirection: Direction = Direction.Unspecified /** Default pretty printing */ def toPrintable: Printable } -- cgit v1.2.3 From eb5e5dc30019be342b7a0534b425bf33b7984ce3 Mon Sep 17 00:00:00 2001 From: Jim Lawson Date: Thu, 29 Sep 2016 11:44:09 -0700 Subject: Massive rename of CompileOptions. Massage CompileOption names in an attempt to preserve default (Strict) CompileOptions in the absence of explicit imports. NOTE: Since the default is now strict, we may encounter errors when we generate connections for clients (i.e., in Vec.do_apply() when we wire up a sequence). We should really thread the CompileOptions through the macro system so the client's implicits are used. --- .../src/main/scala/chisel3/CompileOptions.scala | 53 ++++++++++++++++++++++ .../src/main/scala/chisel3/NotStrict.scala | 16 ------- chiselFrontend/src/main/scala/chisel3/Strict.scala | 16 ------- .../src/main/scala/chisel3/core/Aggregate.scala | 12 ++--- .../src/main/scala/chisel3/core/BiConnect.scala | 6 +-- .../src/main/scala/chisel3/core/Bits.scala | 2 +- .../src/main/scala/chisel3/core/BlackBox.scala | 2 +- .../src/main/scala/chisel3/core/Data.scala | 14 +++--- .../src/main/scala/chisel3/core/Mem.scala | 2 +- .../src/main/scala/chisel3/core/Module.scala | 4 +- .../src/main/scala/chisel3/core/MonoConnect.scala | 6 +-- .../src/main/scala/chisel3/core/Reg.scala | 9 ++-- .../scala/chisel3/internal/CompileOptions.scala | 41 ----------------- 13 files changed, 82 insertions(+), 101 deletions(-) create mode 100644 chiselFrontend/src/main/scala/chisel3/CompileOptions.scala delete mode 100644 chiselFrontend/src/main/scala/chisel3/NotStrict.scala delete mode 100644 chiselFrontend/src/main/scala/chisel3/Strict.scala delete mode 100644 chiselFrontend/src/main/scala/chisel3/internal/CompileOptions.scala (limited to 'chiselFrontend/src') diff --git a/chiselFrontend/src/main/scala/chisel3/CompileOptions.scala b/chiselFrontend/src/main/scala/chisel3/CompileOptions.scala new file mode 100644 index 00000000..2e5c64aa --- /dev/null +++ b/chiselFrontend/src/main/scala/chisel3/CompileOptions.scala @@ -0,0 +1,53 @@ +// See LICENSE for license details. + +package chisel3 + +import scala.language.experimental.macros + +trait CompileOptions { + // Should Bundle connections require a strict match of fields. + // If true and the same fields aren't present in both source and sink, a MissingFieldException, + // MissingLeftFieldException, or MissingRightFieldException will be thrown. + val connectFieldsMustMatch: Boolean + // When creating an object that takes a type argument, the argument must be unbound (a pure type). + val declaredTypeMustBeUnbound: Boolean + // Module IOs should be wrapped in an IO() to define their bindings before the reset of the module is defined. + val requireIOWrap: Boolean + // If a connection operator fails, don't try the connection with the operands (source and sink) reversed. + val dontTryConnectionsSwapped: Boolean + // If connection directionality is not explicit, do not use heuristics to attempt to determine it. + val dontAssumeDirectionality: Boolean +} + +trait ImplicitCompileOptions extends CompileOptions + +object ImplicitCompileOptions { + // Provides a low priority Strict default. Can be overridden by importing the NotStrict option. + implicit def materialize: ImplicitCompileOptions = chisel3.ExplicitCompileOptions.Strict +} + +// Define a more-specific trait which should be perferred if both are available. +trait ExplicitImplicitCompileOptions extends ImplicitCompileOptions + +object ExplicitCompileOptions { + // Collection of "not strict" connection compile options. + // These provide compatibility with existing code. + // import chisel3.ExplicitCompileOptions.NotStrict + implicit object NotStrict extends ExplicitImplicitCompileOptions { + val connectFieldsMustMatch = false + val declaredTypeMustBeUnbound = false + val requireIOWrap = false + val dontTryConnectionsSwapped = false + val dontAssumeDirectionality = false + } + + // Collection of "strict" connection compile options, preferred for new code. + // import chisel3.ExplicitCompileOptions.Strict + implicit object Strict extends ExplicitImplicitCompileOptions { + val connectFieldsMustMatch = true + val declaredTypeMustBeUnbound = true + val requireIOWrap = true + val dontTryConnectionsSwapped = true + val dontAssumeDirectionality = true + } +} diff --git a/chiselFrontend/src/main/scala/chisel3/NotStrict.scala b/chiselFrontend/src/main/scala/chisel3/NotStrict.scala deleted file mode 100644 index bb390e7c..00000000 --- a/chiselFrontend/src/main/scala/chisel3/NotStrict.scala +++ /dev/null @@ -1,16 +0,0 @@ -// See LICENSE for license details. - -package chisel3 - -import chisel3.internal.ExplicitCompileOptions - - -object NotStrict { - implicit object CompileOptions extends ExplicitCompileOptions { - val connectFieldsMustMatch = false - val declaredTypeMustBeUnbound = false - val requireIOWrap = false - val dontTryConnectionsSwapped = false - val dontAssumeDirectionality = false - } -} diff --git a/chiselFrontend/src/main/scala/chisel3/Strict.scala b/chiselFrontend/src/main/scala/chisel3/Strict.scala deleted file mode 100644 index 70240429..00000000 --- a/chiselFrontend/src/main/scala/chisel3/Strict.scala +++ /dev/null @@ -1,16 +0,0 @@ -// See LICENSE for license details. - -package chisel3 - -import chisel3.internal.ExplicitCompileOptions - - -object Strict { - implicit object CompileOptions extends ExplicitCompileOptions { - val connectFieldsMustMatch = true - val declaredTypeMustBeUnbound = true - val requireIOWrap = true - val dontTryConnectionsSwapped = true - val dontAssumeDirectionality = true - } -} diff --git a/chiselFrontend/src/main/scala/chisel3/core/Aggregate.scala b/chiselFrontend/src/main/scala/chisel3/core/Aggregate.scala index a0eefbfe..b363c572 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/Aggregate.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/Aggregate.scala @@ -10,7 +10,7 @@ import chisel3.internal._ import chisel3.internal.Builder.pushCommand import chisel3.internal.firrtl._ import chisel3.internal.sourceinfo.{SourceInfo, DeprecatedSourceInfo, VecTransform, SourceInfoTransform} -import chisel3.NotStrict.CompileOptions +import chisel3.ImplicitCompileOptions /** An abstract class for data types that solely consist of (are an aggregate * of) other Data objects. @@ -152,27 +152,27 @@ sealed class Vec[T <: Data] private (gen: T, val length: Int) * * @note the length of this Vec must match the length of the input Seq */ - def <> (that: Seq[T])(implicit sourceInfo: SourceInfo, moduleCompileOptions: ExplicitCompileOptions): Unit = { + def <> (that: Seq[T])(implicit sourceInfo: SourceInfo, moduleCompileOptions: ImplicitCompileOptions): 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, moduleCompileOptions: ExplicitCompileOptions): Unit = this bulkConnect that.asInstanceOf[Data] + def <> (that: Vec[T])(implicit sourceInfo: SourceInfo, moduleCompileOptions: ImplicitCompileOptions): Unit = this bulkConnect that.asInstanceOf[Data] /** 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, moduleCompileOptions: ExplicitCompileOptions): Unit = { + def := (that: Seq[T])(implicit sourceInfo: SourceInfo, moduleCompileOptions: ImplicitCompileOptions): 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, moduleCompileOptions: ExplicitCompileOptions): Unit = this connect that + def := (that: Vec[T])(implicit sourceInfo: SourceInfo, moduleCompileOptions: ImplicitCompileOptions): Unit = this connect that /** Creates a dynamically indexed read or write accessor into the array. */ @@ -199,7 +199,7 @@ sealed class Vec[T <: Data] private (gen: T, val length: Int) @deprecated("Use Vec.apply instead", "chisel3") def write(idx: UInt, data: T): Unit = { - apply(idx).:=(data)(DeprecatedSourceInfo, chisel3.NotStrict.CompileOptions) + apply(idx).:=(data)(DeprecatedSourceInfo, chisel3.ExplicitCompileOptions.NotStrict) } override def cloneType: this.type = { diff --git a/chiselFrontend/src/main/scala/chisel3/core/BiConnect.scala b/chiselFrontend/src/main/scala/chisel3/core/BiConnect.scala index ce70a19a..a6b9cda3 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/BiConnect.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/BiConnect.scala @@ -6,7 +6,7 @@ import chisel3.internal.Builder.pushCommand import chisel3.internal.firrtl.Connect import scala.language.experimental.macros import chisel3.internal.sourceinfo._ -import chisel3.internal.ExplicitCompileOptions +import chisel3.ImplicitCompileOptions /** * BiConnect.connect executes a bidirectional connection element-wise. @@ -50,7 +50,7 @@ object BiConnect { * 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, connectCompileOptions: ExplicitCompileOptions, left: Data, right: Data, context_mod: Module): Unit = + def connect(sourceInfo: SourceInfo, connectCompileOptions: ImplicitCompileOptions, left: Data, right: Data, context_mod: Module): Unit = (left, right) match { // Handle element case (root case) case (left_e: Element, right_e: Element) => { @@ -110,7 +110,7 @@ object BiConnect { // This function checks if element-level connection operation allowed. // Then it either issues it or throws the appropriate exception. - def elemConnect(implicit sourceInfo: SourceInfo, connectCompileOptions: ExplicitCompileOptions, left: Element, right: Element, context_mod: Module): Unit = { + def elemConnect(implicit sourceInfo: SourceInfo, connectCompileOptions: ImplicitCompileOptions, 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 diff --git a/chiselFrontend/src/main/scala/chisel3/core/Bits.scala b/chiselFrontend/src/main/scala/chisel3/core/Bits.scala index 938eeb1f..12c99104 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/Bits.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/Bits.scala @@ -10,7 +10,7 @@ import chisel3.internal.firrtl._ import chisel3.internal.sourceinfo.{SourceInfo, DeprecatedSourceInfo, SourceInfoTransform, SourceInfoWhiteboxTransform, UIntTransform, MuxTransform} import chisel3.internal.firrtl.PrimOp._ -import chisel3.NotStrict.CompileOptions +//import chisel3.ImplicitCompileOptions.NotStrict /** Element is a leaf data type: it cannot contain other Data objects. Example * uses are for representing primitive data types, like integers and bits. diff --git a/chiselFrontend/src/main/scala/chisel3/core/BlackBox.scala b/chiselFrontend/src/main/scala/chisel3/core/BlackBox.scala index 7b0cf3f7..7e61ec72 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/BlackBox.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/BlackBox.scala @@ -5,7 +5,7 @@ package chisel3.core import chisel3.internal.Builder.pushCommand import chisel3.internal.firrtl.{ModuleIO, DefInvalid} import chisel3.internal.sourceinfo.SourceInfo -import chisel3.NotStrict.CompileOptions +//import chisel3.ExplicitCompileOptions.NotStrict /** 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 diff --git a/chiselFrontend/src/main/scala/chisel3/core/Data.scala b/chiselFrontend/src/main/scala/chisel3/core/Data.scala index 52bc8128..1b08374a 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/Data.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/Data.scala @@ -9,7 +9,7 @@ import chisel3.internal.Builder.{pushCommand, pushOp} import chisel3.internal.firrtl._ import chisel3.internal.sourceinfo.{SourceInfo, DeprecatedSourceInfo, UnlocatableSourceInfo, WireTransform, SourceInfoTransform} import chisel3.internal.firrtl.PrimOp.AsUIntOp -import chisel3.NotStrict.CompileOptions +import chisel3.ImplicitCompileOptions sealed abstract class Direction(name: String) { override def toString: String = name @@ -126,7 +126,7 @@ abstract class Data extends HasId { private[core] def badConnect(that: Data)(implicit sourceInfo: SourceInfo): Unit = throwException(s"cannot connect ${this} and ${that}") - private[chisel3] def connect(that: Data)(implicit sourceInfo: SourceInfo, connectCompileOptions: ExplicitCompileOptions): Unit = { + private[chisel3] def connect(that: Data)(implicit sourceInfo: SourceInfo, connectCompileOptions: ImplicitCompileOptions): Unit = { Binding.checkSynthesizable(this, s"'this' ($this)") Binding.checkSynthesizable(that, s"'that' ($that)") try { @@ -138,7 +138,7 @@ abstract class Data extends HasId { ) } } - private[chisel3] def bulkConnect(that: Data)(implicit sourceInfo: SourceInfo, connectCompileOptions: ExplicitCompileOptions): Unit = { + private[chisel3] def bulkConnect(that: Data)(implicit sourceInfo: SourceInfo, connectCompileOptions: ImplicitCompileOptions): Unit = { Binding.checkSynthesizable(this, s"'this' ($this)") Binding.checkSynthesizable(that, s"'that' ($that)") try { @@ -167,8 +167,8 @@ abstract class Data extends HasId { } clone } - final def := (that: Data)(implicit sourceInfo: SourceInfo, connectionCompileOptions: ExplicitCompileOptions): Unit = this.connect(that)(sourceInfo, connectionCompileOptions) - final def <> (that: Data)(implicit sourceInfo: SourceInfo, connectionCompileOptions: ExplicitCompileOptions): Unit = this.bulkConnect(that)(sourceInfo, connectionCompileOptions) + final def := (that: Data)(implicit sourceInfo: SourceInfo, connectionCompileOptions: ImplicitCompileOptions): Unit = this.connect(that)(sourceInfo, connectionCompileOptions) + final def <> (that: Data)(implicit sourceInfo: SourceInfo, connectionCompileOptions: ImplicitCompileOptions): Unit = this.bulkConnect(that)(sourceInfo, connectionCompileOptions) def litArg(): Option[LitArg] = None def litValue(): BigInt = litArg.get.num def isLit(): Boolean = litArg.isDefined @@ -260,7 +260,7 @@ object Wire { do_apply(t, init)(UnlocatableSourceInfo) def do_apply[T <: Data](t: T, init: T)(implicit sourceInfo: SourceInfo): T = { - val x = Reg.makeType(chisel3.NotStrict.CompileOptions, t, null.asInstanceOf[T], init) + val x = Reg.makeType(chisel3.ExplicitCompileOptions.NotStrict, t, null.asInstanceOf[T], init) // Bind each element of x to being a Wire Binding.bind(x, WireBinder(Builder.forcedModule), "Error: t") @@ -294,7 +294,7 @@ sealed class Clock extends Element(Width(1)) { private[core] def cloneTypeWidth(width: Width): this.type = cloneType private[chisel3] def toType = "Clock" - override def connect (that: Data)(implicit sourceInfo: SourceInfo, connectCompileOptions: ExplicitCompileOptions): Unit = that match { + override def connect (that: Data)(implicit sourceInfo: SourceInfo, connectCompileOptions: ImplicitCompileOptions): Unit = that match { case _: Clock => super.connect(that)(sourceInfo, connectCompileOptions) case _ => super.badConnect(that)(sourceInfo) } diff --git a/chiselFrontend/src/main/scala/chisel3/core/Mem.scala b/chiselFrontend/src/main/scala/chisel3/core/Mem.scala index 5eaaf262..d762ef5e 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/Mem.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/Mem.scala @@ -8,7 +8,7 @@ import chisel3.internal._ import chisel3.internal.Builder.pushCommand import chisel3.internal.firrtl._ import chisel3.internal.sourceinfo.{SourceInfo, DeprecatedSourceInfo, UnlocatableSourceInfo, MemTransform} -import chisel3.NotStrict.CompileOptions +//import chisel3.ExplicitCompileOptions.NotStrict object Mem { @deprecated("Mem argument order should be size, t; this will be removed by the official release", "chisel3") diff --git a/chiselFrontend/src/main/scala/chisel3/core/Module.scala b/chiselFrontend/src/main/scala/chisel3/core/Module.scala index 03e4f1b7..f4b36888 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/Module.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/Module.scala @@ -9,7 +9,7 @@ import chisel3.internal.Builder._ import chisel3.internal.firrtl._ import chisel3.internal.firrtl.{Command => _, _} import chisel3.internal.sourceinfo.{InstTransform, SourceInfo, UnlocatableSourceInfo} -import chisel3.NotStrict.CompileOptions +import chisel3.ImplicitCompileOptions object Module { /** A wrapper method that all Module instantiations must be wrapped in @@ -51,7 +51,7 @@ object Module { */ abstract class Module( override_clock: Option[Clock]=None, override_reset: Option[Bool]=None) - (implicit moduleCompileOptions: ExplicitCompileOptions) + (implicit moduleCompileOptions: ImplicitCompileOptions) extends HasId { // _clock and _reset can be clock and reset in these 2ary constructors // once chisel2 compatibility issues are resolved diff --git a/chiselFrontend/src/main/scala/chisel3/core/MonoConnect.scala b/chiselFrontend/src/main/scala/chisel3/core/MonoConnect.scala index 1925171b..38030d49 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/MonoConnect.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/MonoConnect.scala @@ -6,7 +6,7 @@ import chisel3.internal.Builder.pushCommand import chisel3.internal.firrtl.Connect import scala.language.experimental.macros import chisel3.internal.sourceinfo.{DeprecatedSourceInfo, SourceInfo, SourceInfoTransform, UnlocatableSourceInfo, WireTransform} -import chisel3.internal.ExplicitCompileOptions +import chisel3.ImplicitCompileOptions /** * MonoConnect.connect executes a mono-directional connection element-wise. @@ -56,7 +56,7 @@ object MonoConnect { * 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, connectCompileOptions: ExplicitCompileOptions, sink: Data, source: Data, context_mod: Module): Unit = + def connect(sourceInfo: SourceInfo, connectCompileOptions: ImplicitCompileOptions, sink: Data, source: Data, context_mod: Module): Unit = (sink, source) match { // Handle element case (root case) case (sink_e: Element, source_e: Element) => { @@ -103,7 +103,7 @@ object MonoConnect { // This function checks if element-level connection operation allowed. // Then it either issues it or throws the appropriate exception. - def elemConnect(implicit sourceInfo: SourceInfo, connectCompileOptions: ExplicitCompileOptions, sink: Element, source: Element, context_mod: Module): Unit = { + def elemConnect(implicit sourceInfo: SourceInfo, connectCompileOptions: ImplicitCompileOptions, 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 diff --git a/chiselFrontend/src/main/scala/chisel3/core/Reg.scala b/chiselFrontend/src/main/scala/chisel3/core/Reg.scala index 2569e9ea..1bdfb40f 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/Reg.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/Reg.scala @@ -6,9 +6,10 @@ import chisel3.internal._ import chisel3.internal.Builder.pushCommand import chisel3.internal.firrtl._ import chisel3.internal.sourceinfo.{SourceInfo, UnlocatableSourceInfo} +import chisel3.ImplicitCompileOptions object Reg { - private[core] def makeType[T <: Data](compileOptions: ExplicitCompileOptions, t: T = null, next: T = null, init: T = null): T = { + private[core] def makeType[T <: Data](compileOptions: ImplicitCompileOptions, t: T = null, next: T = null, init: T = null): T = { if (t ne null) { if (compileOptions.declaredTypeMustBeUnbound) { Binding.checkUnbound(t, s"t ($t) must be unbound Type. Try using cloneType?") @@ -40,7 +41,7 @@ object Reg { * 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)(implicit sourceInfo: SourceInfo, compileOptions: ExplicitCompileOptions): T = + def apply[T <: Data](t: T = null, next: T = null, init: T = null)(implicit sourceInfo: SourceInfo, compileOptions: ImplicitCompileOptions): T = // Scala macros can't (yet) handle named or default arguments. do_apply(t, next, init)(sourceInfo, compileOptions) @@ -49,9 +50,9 @@ object Reg { * * @param outType: data type for the register */ - def apply[T <: Data](outType: T)(implicit sourceInfo: SourceInfo, compileOptions: ExplicitCompileOptions): T = Reg[T](outType, null.asInstanceOf[T], null.asInstanceOf[T])(sourceInfo, compileOptions) + def apply[T <: Data](outType: T)(implicit sourceInfo: SourceInfo, compileOptions: ImplicitCompileOptions): T = Reg[T](outType, null.asInstanceOf[T], null.asInstanceOf[T])(sourceInfo, compileOptions) - def do_apply[T <: Data](t: T, next: T, init: T)(implicit sourceInfo: SourceInfo, compileOptions: ExplicitCompileOptions = chisel3.NotStrict.CompileOptions): T = { + def do_apply[T <: Data](t: T, next: T, init: T)(implicit sourceInfo: SourceInfo, compileOptions: ImplicitCompileOptions = chisel3.ExplicitCompileOptions.NotStrict): 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()). diff --git a/chiselFrontend/src/main/scala/chisel3/internal/CompileOptions.scala b/chiselFrontend/src/main/scala/chisel3/internal/CompileOptions.scala deleted file mode 100644 index 2b913908..00000000 --- a/chiselFrontend/src/main/scala/chisel3/internal/CompileOptions.scala +++ /dev/null @@ -1,41 +0,0 @@ -// See LICENSE for license details. - -package chisel3.internal - -import scala.language.experimental.macros -import scala.reflect.macros.blackbox.Context - -trait CompileOptions { - // Should Bundle connections require a strict match of fields. - // If true and the same fields aren't present in both source and sink, a MissingFieldException, - // MissingLeftFieldException, or MissingRightFieldException will be thrown. - val connectFieldsMustMatch: Boolean - val declaredTypeMustBeUnbound: Boolean - val requireIOWrap: Boolean - val dontTryConnectionsSwapped: Boolean - val dontAssumeDirectionality: Boolean -} - -trait ExplicitCompileOptions extends CompileOptions - -object ExplicitCompileOptions { - // Provides a low priority Strict default. Can be overridden by importing the NotStrict option. - implicit def materialize: ExplicitCompileOptions = chisel3.Strict.CompileOptions -} - -///** Initialize compilation options from a string map. -// * -// * @param optionsMap the map from "option" to "value" -// */ -//class CompileOptions(optionsMap: Map[String, String]) { -// // The default for settings related to "strictness". -// val strictDefault: String = optionsMap.getOrElse("strict", "false") -// // Should Bundle connections require a strict match of fields. -// // If true and the same fields aren't present in both source and sink, a MissingFieldException, -// // MissingLeftFieldException, or MissingRightFieldException will be thrown. -// val connectFieldsMustMatch: Boolean = optionsMap.getOrElse("connectFieldsMustMatch", strictDefault).toBoolean -// val declaredTypeMustBeUnbound: Boolean = optionsMap.getOrElse("declaredTypeMustBeUnbound", strictDefault).toBoolean -// val requireIOWrap: Boolean = optionsMap.getOrElse("requireIOWrap", strictDefault).toBoolean -// val dontTryConnectionsSwapped: Boolean = optionsMap.getOrElse("dontTryConnectionsSwapped", strictDefault).toBoolean -// val dontAssumeDirectionality: Boolean = optionsMap.getOrElse("dontAssumeDirectionality", strictDefault).toBoolean -//} -- cgit v1.2.3 From 96fb6a5e2c781b20470d02eac186b1b129c20bdf Mon Sep 17 00:00:00 2001 From: Jim Lawson Date: Thu, 29 Sep 2016 14:57:42 -0700 Subject: Consolidate CompileOptions and re-enable NotStrict pending macro work. --- .../src/main/scala/chisel3/CompileOptions.scala | 53 ---------------------- .../src/main/scala/chisel3/core/Aggregate.scala | 12 ++--- .../src/main/scala/chisel3/core/BiConnect.scala | 6 +-- .../src/main/scala/chisel3/core/Bits.scala | 3 +- .../src/main/scala/chisel3/core/BlackBox.scala | 3 +- .../main/scala/chisel3/core/CompileOptions.scala | 48 ++++++++++++++++++++ .../src/main/scala/chisel3/core/Data.scala | 14 +++--- .../src/main/scala/chisel3/core/Mem.scala | 3 +- .../src/main/scala/chisel3/core/Module.scala | 4 +- .../src/main/scala/chisel3/core/MonoConnect.scala | 6 +-- .../src/main/scala/chisel3/core/Reg.scala | 10 ++-- 11 files changed, 80 insertions(+), 82 deletions(-) delete mode 100644 chiselFrontend/src/main/scala/chisel3/CompileOptions.scala create mode 100644 chiselFrontend/src/main/scala/chisel3/core/CompileOptions.scala (limited to 'chiselFrontend/src') diff --git a/chiselFrontend/src/main/scala/chisel3/CompileOptions.scala b/chiselFrontend/src/main/scala/chisel3/CompileOptions.scala deleted file mode 100644 index 2e5c64aa..00000000 --- a/chiselFrontend/src/main/scala/chisel3/CompileOptions.scala +++ /dev/null @@ -1,53 +0,0 @@ -// See LICENSE for license details. - -package chisel3 - -import scala.language.experimental.macros - -trait CompileOptions { - // Should Bundle connections require a strict match of fields. - // If true and the same fields aren't present in both source and sink, a MissingFieldException, - // MissingLeftFieldException, or MissingRightFieldException will be thrown. - val connectFieldsMustMatch: Boolean - // When creating an object that takes a type argument, the argument must be unbound (a pure type). - val declaredTypeMustBeUnbound: Boolean - // Module IOs should be wrapped in an IO() to define their bindings before the reset of the module is defined. - val requireIOWrap: Boolean - // If a connection operator fails, don't try the connection with the operands (source and sink) reversed. - val dontTryConnectionsSwapped: Boolean - // If connection directionality is not explicit, do not use heuristics to attempt to determine it. - val dontAssumeDirectionality: Boolean -} - -trait ImplicitCompileOptions extends CompileOptions - -object ImplicitCompileOptions { - // Provides a low priority Strict default. Can be overridden by importing the NotStrict option. - implicit def materialize: ImplicitCompileOptions = chisel3.ExplicitCompileOptions.Strict -} - -// Define a more-specific trait which should be perferred if both are available. -trait ExplicitImplicitCompileOptions extends ImplicitCompileOptions - -object ExplicitCompileOptions { - // Collection of "not strict" connection compile options. - // These provide compatibility with existing code. - // import chisel3.ExplicitCompileOptions.NotStrict - implicit object NotStrict extends ExplicitImplicitCompileOptions { - val connectFieldsMustMatch = false - val declaredTypeMustBeUnbound = false - val requireIOWrap = false - val dontTryConnectionsSwapped = false - val dontAssumeDirectionality = false - } - - // Collection of "strict" connection compile options, preferred for new code. - // import chisel3.ExplicitCompileOptions.Strict - implicit object Strict extends ExplicitImplicitCompileOptions { - val connectFieldsMustMatch = true - val declaredTypeMustBeUnbound = true - val requireIOWrap = true - val dontTryConnectionsSwapped = true - val dontAssumeDirectionality = true - } -} diff --git a/chiselFrontend/src/main/scala/chisel3/core/Aggregate.scala b/chiselFrontend/src/main/scala/chisel3/core/Aggregate.scala index b363c572..a28c4bec 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/Aggregate.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/Aggregate.scala @@ -10,7 +10,7 @@ import chisel3.internal._ import chisel3.internal.Builder.pushCommand import chisel3.internal.firrtl._ import chisel3.internal.sourceinfo.{SourceInfo, DeprecatedSourceInfo, VecTransform, SourceInfoTransform} -import chisel3.ImplicitCompileOptions +//import chisel3.CompileOptions /** An abstract class for data types that solely consist of (are an aggregate * of) other Data objects. @@ -152,27 +152,27 @@ sealed class Vec[T <: Data] private (gen: T, val length: Int) * * @note the length of this Vec must match the length of the input Seq */ - def <> (that: Seq[T])(implicit sourceInfo: SourceInfo, moduleCompileOptions: ImplicitCompileOptions): Unit = { + def <> (that: Seq[T])(implicit sourceInfo: SourceInfo, moduleCompileOptions: CompileOptions): 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, moduleCompileOptions: ImplicitCompileOptions): Unit = this bulkConnect that.asInstanceOf[Data] + def <> (that: Vec[T])(implicit sourceInfo: SourceInfo, moduleCompileOptions: CompileOptions): Unit = this bulkConnect that.asInstanceOf[Data] /** 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, moduleCompileOptions: ImplicitCompileOptions): Unit = { + def := (that: Seq[T])(implicit sourceInfo: SourceInfo, moduleCompileOptions: CompileOptions): 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, moduleCompileOptions: ImplicitCompileOptions): Unit = this connect that + def := (that: Vec[T])(implicit sourceInfo: SourceInfo, moduleCompileOptions: CompileOptions): Unit = this connect that /** Creates a dynamically indexed read or write accessor into the array. */ @@ -199,7 +199,7 @@ sealed class Vec[T <: Data] private (gen: T, val length: Int) @deprecated("Use Vec.apply instead", "chisel3") def write(idx: UInt, data: T): Unit = { - apply(idx).:=(data)(DeprecatedSourceInfo, chisel3.ExplicitCompileOptions.NotStrict) + apply(idx).:=(data)(DeprecatedSourceInfo, chisel3.core.ExplicitCompileOptions.NotStrict) } override def cloneType: this.type = { diff --git a/chiselFrontend/src/main/scala/chisel3/core/BiConnect.scala b/chiselFrontend/src/main/scala/chisel3/core/BiConnect.scala index a6b9cda3..16bde731 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/BiConnect.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/BiConnect.scala @@ -6,7 +6,7 @@ import chisel3.internal.Builder.pushCommand import chisel3.internal.firrtl.Connect import scala.language.experimental.macros import chisel3.internal.sourceinfo._ -import chisel3.ImplicitCompileOptions +//import chisel3.CompileOptions /** * BiConnect.connect executes a bidirectional connection element-wise. @@ -50,7 +50,7 @@ object BiConnect { * 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, connectCompileOptions: ImplicitCompileOptions, left: Data, right: Data, context_mod: Module): Unit = + def connect(sourceInfo: SourceInfo, connectCompileOptions: CompileOptions, left: Data, right: Data, context_mod: Module): Unit = (left, right) match { // Handle element case (root case) case (left_e: Element, right_e: Element) => { @@ -110,7 +110,7 @@ object BiConnect { // This function checks if element-level connection operation allowed. // Then it either issues it or throws the appropriate exception. - def elemConnect(implicit sourceInfo: SourceInfo, connectCompileOptions: ImplicitCompileOptions, left: Element, right: Element, context_mod: Module): Unit = { + def elemConnect(implicit sourceInfo: SourceInfo, connectCompileOptions: CompileOptions, 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 diff --git a/chiselFrontend/src/main/scala/chisel3/core/Bits.scala b/chiselFrontend/src/main/scala/chisel3/core/Bits.scala index 12c99104..24abbdba 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/Bits.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/Bits.scala @@ -10,7 +10,8 @@ import chisel3.internal.firrtl._ import chisel3.internal.sourceinfo.{SourceInfo, DeprecatedSourceInfo, SourceInfoTransform, SourceInfoWhiteboxTransform, UIntTransform, MuxTransform} import chisel3.internal.firrtl.PrimOp._ -//import chisel3.ImplicitCompileOptions.NotStrict +// TODO: remove this once we have CompileOptions threaded through the macro system. +import chisel3.core.ExplicitCompileOptions.NotStrict /** Element is a leaf data type: it cannot contain other Data objects. Example * uses are for representing primitive data types, like integers and bits. diff --git a/chiselFrontend/src/main/scala/chisel3/core/BlackBox.scala b/chiselFrontend/src/main/scala/chisel3/core/BlackBox.scala index 7e61ec72..c1352566 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/BlackBox.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/BlackBox.scala @@ -5,7 +5,8 @@ package chisel3.core import chisel3.internal.Builder.pushCommand import chisel3.internal.firrtl.{ModuleIO, DefInvalid} import chisel3.internal.sourceinfo.SourceInfo -//import chisel3.ExplicitCompileOptions.NotStrict +// TODO: remove this once we have CompileOptions threaded through the macro system. +import chisel3.core.ExplicitCompileOptions.NotStrict /** 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 diff --git a/chiselFrontend/src/main/scala/chisel3/core/CompileOptions.scala b/chiselFrontend/src/main/scala/chisel3/core/CompileOptions.scala new file mode 100644 index 00000000..0e66a241 --- /dev/null +++ b/chiselFrontend/src/main/scala/chisel3/core/CompileOptions.scala @@ -0,0 +1,48 @@ +// See LICENSE for license details. + +package chisel3.core + +import scala.language.experimental.macros + +trait CompileOptions { + // Should Bundle connections require a strict match of fields. + // If true and the same fields aren't present in both source and sink, a MissingFieldException, + // MissingLeftFieldException, or MissingRightFieldException will be thrown. + val connectFieldsMustMatch: Boolean + // When creating an object that takes a type argument, the argument must be unbound (a pure type). + val declaredTypeMustBeUnbound: Boolean + // Module IOs should be wrapped in an IO() to define their bindings before the reset of the module is defined. + val requireIOWrap: Boolean + // If a connection operator fails, don't try the connection with the operands (source and sink) reversed. + val dontTryConnectionsSwapped: Boolean + // If connection directionality is not explicit, do not use heuristics to attempt to determine it. + val dontAssumeDirectionality: Boolean +} + +object CompileOptions { + // Provides a low priority Strict default. Can be overridden by importing the NotStrict option. + implicit def materialize: CompileOptions = chisel3.core.ExplicitCompileOptions.Strict +} + +object ExplicitCompileOptions { + // Collection of "not strict" connection compile options. + // These provide compatibility with existing code. + // import chisel3.core.ExplicitCompileOptions.NotStrict + implicit object NotStrict extends CompileOptions { + val connectFieldsMustMatch = false + val declaredTypeMustBeUnbound = false + val requireIOWrap = false + val dontTryConnectionsSwapped = false + val dontAssumeDirectionality = false + } + + // Collection of "strict" connection compile options, preferred for new code. + // import chisel3.core.ExplicitCompileOptions.Strict + implicit object Strict extends CompileOptions { + val connectFieldsMustMatch = true + val declaredTypeMustBeUnbound = true + val requireIOWrap = true + val dontTryConnectionsSwapped = true + val dontAssumeDirectionality = true + } +} diff --git a/chiselFrontend/src/main/scala/chisel3/core/Data.scala b/chiselFrontend/src/main/scala/chisel3/core/Data.scala index 1b08374a..83619fc8 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/Data.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/Data.scala @@ -9,7 +9,7 @@ import chisel3.internal.Builder.{pushCommand, pushOp} import chisel3.internal.firrtl._ import chisel3.internal.sourceinfo.{SourceInfo, DeprecatedSourceInfo, UnlocatableSourceInfo, WireTransform, SourceInfoTransform} import chisel3.internal.firrtl.PrimOp.AsUIntOp -import chisel3.ImplicitCompileOptions +//import chisel3.CompileOptions sealed abstract class Direction(name: String) { override def toString: String = name @@ -126,7 +126,7 @@ abstract class Data extends HasId { private[core] def badConnect(that: Data)(implicit sourceInfo: SourceInfo): Unit = throwException(s"cannot connect ${this} and ${that}") - private[chisel3] def connect(that: Data)(implicit sourceInfo: SourceInfo, connectCompileOptions: ImplicitCompileOptions): Unit = { + private[chisel3] def connect(that: Data)(implicit sourceInfo: SourceInfo, connectCompileOptions: CompileOptions): Unit = { Binding.checkSynthesizable(this, s"'this' ($this)") Binding.checkSynthesizable(that, s"'that' ($that)") try { @@ -138,7 +138,7 @@ abstract class Data extends HasId { ) } } - private[chisel3] def bulkConnect(that: Data)(implicit sourceInfo: SourceInfo, connectCompileOptions: ImplicitCompileOptions): Unit = { + private[chisel3] def bulkConnect(that: Data)(implicit sourceInfo: SourceInfo, connectCompileOptions: CompileOptions): Unit = { Binding.checkSynthesizable(this, s"'this' ($this)") Binding.checkSynthesizable(that, s"'that' ($that)") try { @@ -167,8 +167,8 @@ abstract class Data extends HasId { } clone } - final def := (that: Data)(implicit sourceInfo: SourceInfo, connectionCompileOptions: ImplicitCompileOptions): Unit = this.connect(that)(sourceInfo, connectionCompileOptions) - final def <> (that: Data)(implicit sourceInfo: SourceInfo, connectionCompileOptions: ImplicitCompileOptions): Unit = this.bulkConnect(that)(sourceInfo, connectionCompileOptions) + final def := (that: Data)(implicit sourceInfo: SourceInfo, connectionCompileOptions: CompileOptions): Unit = this.connect(that)(sourceInfo, connectionCompileOptions) + final def <> (that: Data)(implicit sourceInfo: SourceInfo, connectionCompileOptions: CompileOptions): Unit = this.bulkConnect(that)(sourceInfo, connectionCompileOptions) def litArg(): Option[LitArg] = None def litValue(): BigInt = litArg.get.num def isLit(): Boolean = litArg.isDefined @@ -260,7 +260,7 @@ object Wire { do_apply(t, init)(UnlocatableSourceInfo) def do_apply[T <: Data](t: T, init: T)(implicit sourceInfo: SourceInfo): T = { - val x = Reg.makeType(chisel3.ExplicitCompileOptions.NotStrict, t, null.asInstanceOf[T], init) + val x = Reg.makeType(chisel3.core.ExplicitCompileOptions.NotStrict, t, null.asInstanceOf[T], init) // Bind each element of x to being a Wire Binding.bind(x, WireBinder(Builder.forcedModule), "Error: t") @@ -294,7 +294,7 @@ sealed class Clock extends Element(Width(1)) { private[core] def cloneTypeWidth(width: Width): this.type = cloneType private[chisel3] def toType = "Clock" - override def connect (that: Data)(implicit sourceInfo: SourceInfo, connectCompileOptions: ImplicitCompileOptions): Unit = that match { + override def connect (that: Data)(implicit sourceInfo: SourceInfo, connectCompileOptions: CompileOptions): Unit = that match { case _: Clock => super.connect(that)(sourceInfo, connectCompileOptions) case _ => super.badConnect(that)(sourceInfo) } diff --git a/chiselFrontend/src/main/scala/chisel3/core/Mem.scala b/chiselFrontend/src/main/scala/chisel3/core/Mem.scala index d762ef5e..b24d463a 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/Mem.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/Mem.scala @@ -8,7 +8,8 @@ import chisel3.internal._ import chisel3.internal.Builder.pushCommand import chisel3.internal.firrtl._ import chisel3.internal.sourceinfo.{SourceInfo, DeprecatedSourceInfo, UnlocatableSourceInfo, MemTransform} -//import chisel3.ExplicitCompileOptions.NotStrict +// TODO: remove this once we have CompileOptions threaded through the macro system. +import chisel3.core.ExplicitCompileOptions.NotStrict object Mem { @deprecated("Mem argument order should be size, t; this will be removed by the official release", "chisel3") diff --git a/chiselFrontend/src/main/scala/chisel3/core/Module.scala b/chiselFrontend/src/main/scala/chisel3/core/Module.scala index f4b36888..55ef7491 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/Module.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/Module.scala @@ -9,7 +9,7 @@ import chisel3.internal.Builder._ import chisel3.internal.firrtl._ import chisel3.internal.firrtl.{Command => _, _} import chisel3.internal.sourceinfo.{InstTransform, SourceInfo, UnlocatableSourceInfo} -import chisel3.ImplicitCompileOptions +//import chisel3.CompileOptions object Module { /** A wrapper method that all Module instantiations must be wrapped in @@ -51,7 +51,7 @@ object Module { */ abstract class Module( override_clock: Option[Clock]=None, override_reset: Option[Bool]=None) - (implicit moduleCompileOptions: ImplicitCompileOptions) + (implicit moduleCompileOptions: CompileOptions) extends HasId { // _clock and _reset can be clock and reset in these 2ary constructors // once chisel2 compatibility issues are resolved diff --git a/chiselFrontend/src/main/scala/chisel3/core/MonoConnect.scala b/chiselFrontend/src/main/scala/chisel3/core/MonoConnect.scala index 38030d49..48efda4d 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/MonoConnect.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/MonoConnect.scala @@ -6,7 +6,7 @@ import chisel3.internal.Builder.pushCommand import chisel3.internal.firrtl.Connect import scala.language.experimental.macros import chisel3.internal.sourceinfo.{DeprecatedSourceInfo, SourceInfo, SourceInfoTransform, UnlocatableSourceInfo, WireTransform} -import chisel3.ImplicitCompileOptions +//import chisel3.CompileOptions /** * MonoConnect.connect executes a mono-directional connection element-wise. @@ -56,7 +56,7 @@ object MonoConnect { * 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, connectCompileOptions: ImplicitCompileOptions, sink: Data, source: Data, context_mod: Module): Unit = + def connect(sourceInfo: SourceInfo, connectCompileOptions: CompileOptions, sink: Data, source: Data, context_mod: Module): Unit = (sink, source) match { // Handle element case (root case) case (sink_e: Element, source_e: Element) => { @@ -103,7 +103,7 @@ object MonoConnect { // This function checks if element-level connection operation allowed. // Then it either issues it or throws the appropriate exception. - def elemConnect(implicit sourceInfo: SourceInfo, connectCompileOptions: ImplicitCompileOptions, sink: Element, source: Element, context_mod: Module): Unit = { + def elemConnect(implicit sourceInfo: SourceInfo, connectCompileOptions: CompileOptions, 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 diff --git a/chiselFrontend/src/main/scala/chisel3/core/Reg.scala b/chiselFrontend/src/main/scala/chisel3/core/Reg.scala index 1bdfb40f..30c2b3cd 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/Reg.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/Reg.scala @@ -6,10 +6,10 @@ import chisel3.internal._ import chisel3.internal.Builder.pushCommand import chisel3.internal.firrtl._ import chisel3.internal.sourceinfo.{SourceInfo, UnlocatableSourceInfo} -import chisel3.ImplicitCompileOptions +//import chisel3.CompileOptions object Reg { - private[core] def makeType[T <: Data](compileOptions: ImplicitCompileOptions, t: T = null, next: T = null, init: T = null): T = { + private[core] def makeType[T <: Data](compileOptions: CompileOptions, t: T = null, next: T = null, init: T = null): T = { if (t ne null) { if (compileOptions.declaredTypeMustBeUnbound) { Binding.checkUnbound(t, s"t ($t) must be unbound Type. Try using cloneType?") @@ -41,7 +41,7 @@ object Reg { * 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)(implicit sourceInfo: SourceInfo, compileOptions: ImplicitCompileOptions): T = + def apply[T <: Data](t: T = null, next: T = null, init: T = null)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): T = // Scala macros can't (yet) handle named or default arguments. do_apply(t, next, init)(sourceInfo, compileOptions) @@ -50,9 +50,9 @@ object Reg { * * @param outType: data type for the register */ - def apply[T <: Data](outType: T)(implicit sourceInfo: SourceInfo, compileOptions: ImplicitCompileOptions): T = Reg[T](outType, null.asInstanceOf[T], null.asInstanceOf[T])(sourceInfo, compileOptions) + def apply[T <: Data](outType: T)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): T = Reg[T](outType, null.asInstanceOf[T], null.asInstanceOf[T])(sourceInfo, compileOptions) - def do_apply[T <: Data](t: T, next: T, init: T)(implicit sourceInfo: SourceInfo, compileOptions: ImplicitCompileOptions = chisel3.ExplicitCompileOptions.NotStrict): T = { + def do_apply[T <: Data](t: T, next: T, init: T)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions = chisel3.core.ExplicitCompileOptions.NotStrict): 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()). -- cgit v1.2.3 From 398edafd809c3abda751432c51a07b6b1158ecbd Mon Sep 17 00:00:00 2001 From: Jim Lawson Date: Thu, 29 Sep 2016 15:43:34 -0700 Subject: Manual dead code elimination. --- chiselFrontend/src/main/scala/chisel3/core/Aggregate.scala | 1 - chiselFrontend/src/main/scala/chisel3/core/BiConnect.scala | 1 - chiselFrontend/src/main/scala/chisel3/core/Data.scala | 1 - chiselFrontend/src/main/scala/chisel3/core/Module.scala | 1 - chiselFrontend/src/main/scala/chisel3/core/MonoConnect.scala | 1 - chiselFrontend/src/main/scala/chisel3/core/Reg.scala | 1 - 6 files changed, 6 deletions(-) (limited to 'chiselFrontend/src') diff --git a/chiselFrontend/src/main/scala/chisel3/core/Aggregate.scala b/chiselFrontend/src/main/scala/chisel3/core/Aggregate.scala index a28c4bec..5cec54c2 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/Aggregate.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/Aggregate.scala @@ -10,7 +10,6 @@ import chisel3.internal._ import chisel3.internal.Builder.pushCommand import chisel3.internal.firrtl._ import chisel3.internal.sourceinfo.{SourceInfo, DeprecatedSourceInfo, VecTransform, SourceInfoTransform} -//import chisel3.CompileOptions /** An abstract class for data types that solely consist of (are an aggregate * of) other Data objects. diff --git a/chiselFrontend/src/main/scala/chisel3/core/BiConnect.scala b/chiselFrontend/src/main/scala/chisel3/core/BiConnect.scala index 16bde731..efecf343 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/BiConnect.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/BiConnect.scala @@ -6,7 +6,6 @@ import chisel3.internal.Builder.pushCommand import chisel3.internal.firrtl.Connect import scala.language.experimental.macros import chisel3.internal.sourceinfo._ -//import chisel3.CompileOptions /** * BiConnect.connect executes a bidirectional connection element-wise. diff --git a/chiselFrontend/src/main/scala/chisel3/core/Data.scala b/chiselFrontend/src/main/scala/chisel3/core/Data.scala index 83619fc8..3f21a34c 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/Data.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/Data.scala @@ -9,7 +9,6 @@ import chisel3.internal.Builder.{pushCommand, pushOp} import chisel3.internal.firrtl._ import chisel3.internal.sourceinfo.{SourceInfo, DeprecatedSourceInfo, UnlocatableSourceInfo, WireTransform, SourceInfoTransform} import chisel3.internal.firrtl.PrimOp.AsUIntOp -//import chisel3.CompileOptions sealed abstract class Direction(name: String) { override def toString: String = name diff --git a/chiselFrontend/src/main/scala/chisel3/core/Module.scala b/chiselFrontend/src/main/scala/chisel3/core/Module.scala index 55ef7491..6fb6d036 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/Module.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/Module.scala @@ -9,7 +9,6 @@ import chisel3.internal.Builder._ import chisel3.internal.firrtl._ import chisel3.internal.firrtl.{Command => _, _} import chisel3.internal.sourceinfo.{InstTransform, SourceInfo, UnlocatableSourceInfo} -//import chisel3.CompileOptions object Module { /** A wrapper method that all Module instantiations must be wrapped in diff --git a/chiselFrontend/src/main/scala/chisel3/core/MonoConnect.scala b/chiselFrontend/src/main/scala/chisel3/core/MonoConnect.scala index 48efda4d..ef48709b 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/MonoConnect.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/MonoConnect.scala @@ -6,7 +6,6 @@ import chisel3.internal.Builder.pushCommand import chisel3.internal.firrtl.Connect import scala.language.experimental.macros import chisel3.internal.sourceinfo.{DeprecatedSourceInfo, SourceInfo, SourceInfoTransform, UnlocatableSourceInfo, WireTransform} -//import chisel3.CompileOptions /** * MonoConnect.connect executes a mono-directional connection element-wise. diff --git a/chiselFrontend/src/main/scala/chisel3/core/Reg.scala b/chiselFrontend/src/main/scala/chisel3/core/Reg.scala index 30c2b3cd..9d380695 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/Reg.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/Reg.scala @@ -6,7 +6,6 @@ import chisel3.internal._ import chisel3.internal.Builder.pushCommand import chisel3.internal.firrtl._ import chisel3.internal.sourceinfo.{SourceInfo, UnlocatableSourceInfo} -//import chisel3.CompileOptions object Reg { private[core] def makeType[T <: Data](compileOptions: CompileOptions, t: T = null, next: T = null, init: T = null): T = { -- cgit v1.2.3 From 095fd80cc1250f5ec242fde6ccc9271665f784b2 Mon Sep 17 00:00:00 2001 From: Jim Lawson Date: Tue, 4 Oct 2016 11:46:13 -0700 Subject: Add CompileOptions implicits to all Module constructors - fix #310. (#311) --- chiselFrontend/src/main/scala/chisel3/core/Module.scala | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'chiselFrontend/src') diff --git a/chiselFrontend/src/main/scala/chisel3/core/Module.scala b/chiselFrontend/src/main/scala/chisel3/core/Module.scala index 6fb6d036..55522b4a 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/Module.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/Module.scala @@ -54,9 +54,9 @@ abstract class Module( 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)) + def this(_clock: Clock)(implicit moduleCompileOptions: CompileOptions) = this(Option(_clock), None)(moduleCompileOptions) + def this(_reset: Bool)(implicit moduleCompileOptions: CompileOptions) = this(None, Option(_reset))(moduleCompileOptions) + def this(_clock: Clock, _reset: Bool)(implicit moduleCompileOptions: CompileOptions) = this(Option(_clock), Option(_reset))(moduleCompileOptions) // This function binds the iodef as a port in the hardware graph private[chisel3] def Port[T<:Data](iodef: T): iodef.type = { -- cgit v1.2.3 From c24fc9b93d440cd5604b5c83e5b79b80d9c7604c Mon Sep 17 00:00:00 2001 From: Andrew Waterman Date: Tue, 4 Oct 2016 17:30:46 -0700 Subject: Suppress some scala compiler warnings @unchecked is better than matching on _ in this case, because we want to fail on an unexpected case, rather than silently proceed. --- chiselFrontend/src/main/scala/chisel3/core/BiConnect.scala | 8 ++++---- chiselFrontend/src/main/scala/chisel3/core/MonoConnect.scala | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) (limited to 'chiselFrontend/src') diff --git a/chiselFrontend/src/main/scala/chisel3/core/BiConnect.scala b/chiselFrontend/src/main/scala/chisel3/core/BiConnect.scala index efecf343..2599a20a 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/BiConnect.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/BiConnect.scala @@ -124,7 +124,7 @@ object BiConnect { 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 { + ((left_direction, right_direction): @unchecked) match { // CURRENT MOD CHILD MOD case (Some(Input), Some(Input)) => issueConnectL2R(left, right) case (None, Some(Input)) => issueConnectL2R(left, right) @@ -142,7 +142,7 @@ object BiConnect { 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 { + ((left_direction, right_direction): @unchecked) match { // CHILD MOD CURRENT MOD case (Some(Input), Some(Input)) => issueConnectR2L(left, right) case (Some(Input), None) => issueConnectR2L(left, right) @@ -158,7 +158,7 @@ object BiConnect { // 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 { + ((left_direction, right_direction): @unchecked) match { // CURRENT MOD CURRENT MOD case (Some(Input), Some(Output)) => issueConnectL2R(left, right) case (Some(Input), None) => issueConnectL2R(left, right) @@ -209,7 +209,7 @@ object BiConnect { (right_mod._parent.map(_ == context_mod).getOrElse(false)) ) { // Thus both nodes must be ports and have a direction hint - (left_direction, right_direction) match { + ((left_direction, right_direction): @unchecked) match { // CHILD MOD CHILD MOD case (Some(Input), Some(Output)) => issueConnectR2L(left, right) case (Some(Output), Some(Input)) => issueConnectL2R(left, right) diff --git a/chiselFrontend/src/main/scala/chisel3/core/MonoConnect.scala b/chiselFrontend/src/main/scala/chisel3/core/MonoConnect.scala index ef48709b..fcb14e6f 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/MonoConnect.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/MonoConnect.scala @@ -115,7 +115,7 @@ object MonoConnect { // 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_direction, source_direction): @unchecked) match { // SINK SOURCE // CURRENT MOD CURRENT MOD case (Some(Output), _) => issueConnect(sink, source) @@ -128,7 +128,7 @@ object MonoConnect { 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_direction, source_direction): @unchecked) match { // SINK SOURCE // CURRENT MOD CHILD MOD case (None, Some(Output)) => issueConnect(sink, source) @@ -151,7 +151,7 @@ object MonoConnect { 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_direction, source_direction): @unchecked) match { // SINK SOURCE // CHILD MOD CURRENT MOD case (Some(Input), _) => issueConnect(sink, source) @@ -167,7 +167,7 @@ object MonoConnect { (source_mod._parent.map(_ == context_mod).getOrElse(false)) ) { // Thus both nodes must be ports and have a direction - (sink_direction, source_direction) match { + ((sink_direction, source_direction): @unchecked) match { // SINK SOURCE // CHILD MOD CHILD MOD case (Some(Input), Some(Input)) => issueConnect(sink, source) -- cgit v1.2.3 From b2373ebda5e63fa850de21585307013f8419320a Mon Sep 17 00:00:00 2001 From: Andrew Waterman Date: Wed, 5 Oct 2016 15:18:25 -0700 Subject: Make asInput/asOutput/flip deprecation warnings dynamic Code that imports Chisel._ shouldn't see them. Not sure if requireIOWrap is the right condition... or if cyan is a good choice of color for deprecation warnings. --- .../main/scala/chisel3/core/CompileOptions.scala | 5 +++++ .../src/main/scala/chisel3/core/Data.scala | 21 +++++++++++++++------ .../src/main/scala/chisel3/internal/Builder.scala | 2 ++ .../src/main/scala/chisel3/internal/Error.scala | 8 ++++++++ 4 files changed, 30 insertions(+), 6 deletions(-) (limited to 'chiselFrontend/src') diff --git a/chiselFrontend/src/main/scala/chisel3/core/CompileOptions.scala b/chiselFrontend/src/main/scala/chisel3/core/CompileOptions.scala index 0e66a241..85aa8cdc 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/CompileOptions.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/CompileOptions.scala @@ -17,6 +17,9 @@ trait CompileOptions { val dontTryConnectionsSwapped: Boolean // If connection directionality is not explicit, do not use heuristics to attempt to determine it. val dontAssumeDirectionality: Boolean + // Issue a deprecation warning if Data.{flip, asInput,asOutput} is used + // instead of Flipped, Input, or Output. + val deprecateOldDirectionMethods: Boolean } object CompileOptions { @@ -34,6 +37,7 @@ object ExplicitCompileOptions { val requireIOWrap = false val dontTryConnectionsSwapped = false val dontAssumeDirectionality = false + val deprecateOldDirectionMethods = false } // Collection of "strict" connection compile options, preferred for new code. @@ -44,5 +48,6 @@ object ExplicitCompileOptions { val requireIOWrap = true val dontTryConnectionsSwapped = true val dontAssumeDirectionality = true + val deprecateOldDirectionMethods = true } } diff --git a/chiselFrontend/src/main/scala/chisel3/core/Data.scala b/chiselFrontend/src/main/scala/chisel3/core/Data.scala index 3f21a34c..922b33a9 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/Data.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/Data.scala @@ -104,12 +104,21 @@ object Data { } implicit class AddDirectionToData[T<:Data](val target: T) extends AnyVal { - @deprecated("Input(Data) should be used over Data.asInput", "gchisel") - def asInput: T = Input(target) - @deprecated("Output(Data) should be used over Data.asOutput", "gchisel") - def asOutput: T = Output(target) - @deprecated("Flipped(Data) should be used over Data.flip", "gchisel") - def flip(): T = Flipped(target) + def asInput(implicit opts: CompileOptions): T = { + if (opts.deprecateOldDirectionMethods) + Builder.deprecated("Input(Data) should be used over Data.asInput") + Input(target) + } + def asOutput(implicit opts: CompileOptions): T = { + if (opts.deprecateOldDirectionMethods) + Builder.deprecated("Output(Data) should be used over Data.asOutput") + Output(target) + } + def flip()(implicit opts: CompileOptions): T = { + if (opts.deprecateOldDirectionMethods) + Builder.deprecated("Flipped(Data) should be used over Data.flip") + Flipped(target) + } } } diff --git a/chiselFrontend/src/main/scala/chisel3/internal/Builder.scala b/chiselFrontend/src/main/scala/chisel3/internal/Builder.scala index 8d376810..12cc840e 100644 --- a/chiselFrontend/src/main/scala/chisel3/internal/Builder.scala +++ b/chiselFrontend/src/main/scala/chisel3/internal/Builder.scala @@ -173,6 +173,8 @@ private[chisel3] object Builder { def errors: ErrorLog = dynamicContext.errors def error(m: => String): Unit = errors.error(m) + def warning(m: => String): Unit = errors.warning(m) + def deprecated(m: => String): Unit = errors.deprecated(m) def build[T <: Module](f: => T): Circuit = { dynamicContextVar.withValue(Some(new DynamicContext())) { diff --git a/chiselFrontend/src/main/scala/chisel3/internal/Error.scala b/chiselFrontend/src/main/scala/chisel3/internal/Error.scala index 7ae0580f..c5c67da4 100644 --- a/chiselFrontend/src/main/scala/chisel3/internal/Error.scala +++ b/chiselFrontend/src/main/scala/chisel3/internal/Error.scala @@ -25,6 +25,10 @@ private[chisel3] class ErrorLog { def warning(m: => String): Unit = errors += new Warning(m, getUserLineNumber) + /** Log a deprecation warning message */ + def deprecated(m: => String): Unit = + errors += new DeprecationWarning(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 @@ -86,6 +90,10 @@ private class Warning(msg: => String, line: Option[StackTraceElement]) extends L def format: String = tag("warn", Console.YELLOW) } +private class DeprecationWarning(msg: => String, line: Option[StackTraceElement]) extends LogEntry(msg, line) { + def format: String = tag("warn", Console.CYAN) +} + private class Info(msg: => String, line: Option[StackTraceElement]) extends LogEntry(msg, line) { def format: String = tag("info", Console.MAGENTA) } -- cgit v1.2.3 From a18002c879d14b6c51cd49311a3b2a99a6a204fc Mon Sep 17 00:00:00 2001 From: Andrew Waterman Date: Wed, 5 Oct 2016 14:16:13 -0700 Subject: Give <> and := legacy behavior in compatibility mode --- .../src/main/scala/chisel3/core/Aggregate.scala | 2 + .../src/main/scala/chisel3/core/Bits.scala | 5 ++- .../main/scala/chisel3/core/CompileOptions.scala | 4 ++ .../src/main/scala/chisel3/core/Data.scala | 45 +++++++++++++--------- 4 files changed, 37 insertions(+), 19 deletions(-) (limited to 'chiselFrontend/src') diff --git a/chiselFrontend/src/main/scala/chisel3/core/Aggregate.scala b/chiselFrontend/src/main/scala/chisel3/core/Aggregate.scala index 5cec54c2..98455f4d 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/Aggregate.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/Aggregate.scala @@ -17,6 +17,8 @@ import chisel3.internal.sourceinfo.{SourceInfo, DeprecatedSourceInfo, VecTransfo sealed abstract class Aggregate extends Data { private[core] def cloneTypeWidth(width: Width): this.type = cloneType private[core] def width: Width = flatten.map(_.width).reduce(_ + _) + private[core] def legacyConnect(that: Data)(implicit sourceInfo: SourceInfo): Unit = + pushCommand(BulkConnect(sourceInfo, this.lref, that.lref)) } object Vec { diff --git a/chiselFrontend/src/main/scala/chisel3/core/Bits.scala b/chiselFrontend/src/main/scala/chisel3/core/Bits.scala index 24abbdba..741f6aee 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/Bits.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/Bits.scala @@ -5,7 +5,7 @@ package chisel3.core import scala.language.experimental.macros import chisel3.internal._ -import chisel3.internal.Builder.pushOp +import chisel3.internal.Builder.{pushCommand, pushOp} import chisel3.internal.firrtl._ import chisel3.internal.sourceinfo.{SourceInfo, DeprecatedSourceInfo, SourceInfoTransform, SourceInfoWhiteboxTransform, UIntTransform, MuxTransform} @@ -40,6 +40,9 @@ abstract class Element(private[core] val width: Width) extends Data { private[chisel3] final def allElements: Seq[Element] = Seq(this) def widthKnown: Boolean = width.known def name: String = getRef.name + + private[core] def legacyConnect(that: Data)(implicit sourceInfo: SourceInfo): Unit = + pushCommand(Connect(sourceInfo, this.lref, that.ref)) } /** A data type for values represented by a single bitvector. Provides basic diff --git a/chiselFrontend/src/main/scala/chisel3/core/CompileOptions.scala b/chiselFrontend/src/main/scala/chisel3/core/CompileOptions.scala index 85aa8cdc..4dea39b5 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/CompileOptions.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/CompileOptions.scala @@ -20,6 +20,8 @@ trait CompileOptions { // Issue a deprecation warning if Data.{flip, asInput,asOutput} is used // instead of Flipped, Input, or Output. val deprecateOldDirectionMethods: Boolean + // Check that referenced Data have actually been declared. + val checkSynthesizable: Boolean } object CompileOptions { @@ -38,6 +40,7 @@ object ExplicitCompileOptions { val dontTryConnectionsSwapped = false val dontAssumeDirectionality = false val deprecateOldDirectionMethods = false + val checkSynthesizable = false } // Collection of "strict" connection compile options, preferred for new code. @@ -49,5 +52,6 @@ object ExplicitCompileOptions { val dontTryConnectionsSwapped = true val dontAssumeDirectionality = true val deprecateOldDirectionMethods = true + val checkSynthesizable = true } } diff --git a/chiselFrontend/src/main/scala/chisel3/core/Data.scala b/chiselFrontend/src/main/scala/chisel3/core/Data.scala index 922b33a9..4167be98 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/Data.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/Data.scala @@ -135,27 +135,35 @@ abstract class Data extends HasId { private[core] def badConnect(that: Data)(implicit sourceInfo: SourceInfo): Unit = throwException(s"cannot connect ${this} and ${that}") private[chisel3] def connect(that: Data)(implicit sourceInfo: SourceInfo, connectCompileOptions: CompileOptions): Unit = { - Binding.checkSynthesizable(this, s"'this' ($this)") - Binding.checkSynthesizable(that, s"'that' ($that)") - try { - MonoConnect.connect(sourceInfo, connectCompileOptions, this, that, Builder.forcedModule) - } catch { - case MonoConnect.MonoConnectException(message) => - throwException( - s"Connection between sink ($this) and source ($that) failed @$message" - ) + if (connectCompileOptions.checkSynthesizable) { + Binding.checkSynthesizable(this, s"'this' ($this)") + Binding.checkSynthesizable(that, s"'that' ($that)") + try { + MonoConnect.connect(sourceInfo, connectCompileOptions, this, that, Builder.forcedModule) + } catch { + case MonoConnect.MonoConnectException(message) => + throwException( + s"Connection between sink ($this) and source ($that) failed @$message" + ) + } + } else { + this legacyConnect that } } private[chisel3] def bulkConnect(that: Data)(implicit sourceInfo: SourceInfo, connectCompileOptions: CompileOptions): Unit = { - Binding.checkSynthesizable(this, s"'this' ($this)") - Binding.checkSynthesizable(that, s"'that' ($that)") - try { - BiConnect.connect(sourceInfo, connectCompileOptions, this, that, Builder.forcedModule) - } catch { - case BiConnect.BiConnectException(message) => - throwException( - s"Connection between left ($this) and source ($that) failed @$message" - ) + if (connectCompileOptions.checkSynthesizable) { + Binding.checkSynthesizable(this, s"'this' ($this)") + Binding.checkSynthesizable(that, s"'that' ($that)") + try { + BiConnect.connect(sourceInfo, connectCompileOptions, this, that, Builder.forcedModule) + } catch { + case BiConnect.BiConnectException(message) => + throwException( + s"Connection between left ($this) and source ($that) failed @$message" + ) + } + } else { + this legacyConnect that } } private[chisel3] def lref: Node = Node(this) @@ -163,6 +171,7 @@ abstract class Data extends HasId { private[core] def cloneTypeWidth(width: Width): this.type private[chisel3] def toType: String private[core] def width: Width + private[core] def legacyConnect(that: Data)(implicit sourceInfo: SourceInfo): Unit def cloneType: this.type def chiselCloneType: this.type = { -- cgit v1.2.3 From 7981c6d9e6d25fb27b25e1427794775c9f934a09 Mon Sep 17 00:00:00 2001 From: Andrew Waterman Date: Wed, 5 Oct 2016 15:32:23 -0700 Subject: Use modulo addressing for dynamic Vec/Mem accesses Static accesses are strictly checked. --- chiselFrontend/src/main/scala/chisel3/core/Aggregate.scala | 14 ++++++++++++-- chiselFrontend/src/main/scala/chisel3/core/Mem.scala | 8 ++++++-- 2 files changed, 18 insertions(+), 4 deletions(-) (limited to 'chiselFrontend/src') diff --git a/chiselFrontend/src/main/scala/chisel3/core/Aggregate.scala b/chiselFrontend/src/main/scala/chisel3/core/Aggregate.scala index 5cec54c2..7b759493 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/Aggregate.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/Aggregate.scala @@ -9,7 +9,7 @@ import scala.language.experimental.macros import chisel3.internal._ import chisel3.internal.Builder.pushCommand import chisel3.internal.firrtl._ -import chisel3.internal.sourceinfo.{SourceInfo, DeprecatedSourceInfo, VecTransform, SourceInfoTransform} +import chisel3.internal.sourceinfo.{SourceInfo, DeprecatedSourceInfo, VecTransform, SourceInfoTransform, UnlocatableSourceInfo} /** An abstract class for data types that solely consist of (are an aggregate * of) other Data objects. @@ -113,6 +113,15 @@ object Vec { def do_fill[T <: Data](n: Int)(gen: => T)(implicit sourceInfo: SourceInfo): Vec[T] = apply(Seq.fill(n)(gen)) + + /** Truncate an index to implement modulo-power-of-2 addressing. */ + private[core] def truncateIndex(idx: UInt, n: Int)(implicit sourceInfo: SourceInfo): UInt = { + val w = BigInt(n-1).bitLength + if (n <= 1) UInt(0) + else if (idx.width.known && idx.width.get <= w) idx + else if (idx.width.known) idx(w-1,0) + else Wire(UInt(width = w), init = idx) + } } /** A vector (array) of [[Data]] elements. Provides hardware versions of various @@ -178,7 +187,8 @@ sealed class Vec[T <: Data] private (gen: T, val length: Int) def apply(idx: UInt): T = { Binding.checkSynthesizable(idx ,s"'idx' ($idx)") val port = sample_element.chiselCloneType - port.setRef(this, idx) //TODO(twigg): This is a bit too magical + val i = Vec.truncateIndex(idx, length)(UnlocatableSourceInfo) + port.setRef(this, i) // Bind each element of port to being whatever the base type is // Using the head element as the sample_element diff --git a/chiselFrontend/src/main/scala/chisel3/core/Mem.scala b/chiselFrontend/src/main/scala/chisel3/core/Mem.scala index b24d463a..9cd5a4d8 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/Mem.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/Mem.scala @@ -38,7 +38,10 @@ sealed abstract class MemBase[T <: Data](t: T, val length: Int) extends HasId wi /** 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)) + def apply(idx: Int): T = { + require(idx >= 0 && idx < length) + 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. @@ -85,10 +88,11 @@ sealed abstract class MemBase[T <: Data](t: T, val length: Int) extends HasId wi private def makePort(sourceInfo: SourceInfo, idx: UInt, dir: MemPortDirection): T = { Binding.checkSynthesizable(idx, s"'idx' ($idx)") + val i = Vec.truncateIndex(idx, length)(sourceInfo) val port = pushCommand( DefMemPort(sourceInfo, - t.chiselCloneType, Node(this), dir, idx.ref, Node(idx._parent.get.clock)) + t.chiselCloneType, Node(this), dir, i.ref, Node(i._parent.get.clock)) ).id // Bind each element of port to being a MemoryPort Binding.bind(port, MemoryPortBinder(Builder.forcedModule), "Error: Fresh t") -- cgit v1.2.3 From 36f42c8dff2413f76d9672e92c4457e3a724f4bd Mon Sep 17 00:00:00 2001 From: Jim Lawson Date: Wed, 5 Oct 2016 17:02:53 -0700 Subject: Update @sdtwigg's PR #199 - Add Assert Data. --- chiselFrontend/src/main/scala/chisel3/core/Assert.scala | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) (limited to 'chiselFrontend/src') diff --git a/chiselFrontend/src/main/scala/chisel3/core/Assert.scala b/chiselFrontend/src/main/scala/chisel3/core/Assert.scala index db62f4a8..4782a845 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/Assert.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/Assert.scala @@ -24,21 +24,22 @@ object assert { // scalastyle:ignore object.name * * @param cond condition, assertion fires (simulation fails) when false * @param message optional message to print when the assertion fires + * @param data optional bits to print in the message formatting * * @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, message: String, data: Bits*)(implicit sourceInfo: SourceInfo): Unit = macro apply_impl_msg_data 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 = { + def apply_impl_msg_data(c: Context)(cond: c.Tree, message: c.Tree, data: 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)" + q"$apply_impl_do($cond, $condStr, _root_.scala.Some($message), ..$data)($sourceInfo)" } def apply_impl(c: Context)(cond: c.Tree)(sourceInfo: c.Tree): c.Tree = { @@ -49,11 +50,11 @@ object assert { // scalastyle:ignore object.name q"$apply_impl_do($cond, $condStr, _root_.scala.None)($sourceInfo)" } - def apply_impl_do(cond: Bool, line: String, message: Option[String])(implicit sourceInfo: SourceInfo) { + def apply_impl_do(cond: Bool, line: String, message: Option[String], data: Bits*)(implicit sourceInfo: SourceInfo) { when (!(cond || Builder.forcedModule.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") + case Some(str) => printf.printfWithoutReset(s"Assertion failed: $str\n at $line\n", data:_*) + case None => printf.printfWithoutReset(s"Assertion failed\n at $line\n", data:_*) } pushCommand(Stop(sourceInfo, Node(Builder.forcedModule.clock), 1)) } -- cgit v1.2.3