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 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 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 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 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 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