summaryrefslogtreecommitdiff
path: root/core
diff options
context:
space:
mode:
authorJack Koenig2020-03-22 18:13:58 -0700
committerJack Koenig2020-03-25 19:17:15 -0700
commitfbf5e6f1a0e8bf535d465b748ad554575fe62156 (patch)
tree578858ab6d219ca6daf44cf87b73f75054989097 /core
parentb2e004fb615a3c931d910a338b9faa99c1c975d7 (diff)
Rename subprojects to more canonical names
* Rename coreMacros to macros * Rename chiselFrontend to core Also make each subproject publish with "chisel3-" as a prefix
Diffstat (limited to 'core')
-rw-r--r--core/src/main/scala/chisel3/Aggregate.scala1016
-rw-r--r--core/src/main/scala/chisel3/Annotation.scala94
-rw-r--r--core/src/main/scala/chisel3/Assert.scala92
-rw-r--r--core/src/main/scala/chisel3/Attach.scala46
-rw-r--r--core/src/main/scala/chisel3/Bits.scala2289
-rw-r--r--core/src/main/scala/chisel3/BlackBox.scala181
-rw-r--r--core/src/main/scala/chisel3/BoolFactory.scala22
-rw-r--r--core/src/main/scala/chisel3/Clock.scala43
-rw-r--r--core/src/main/scala/chisel3/CompileOptions.scala80
-rw-r--r--core/src/main/scala/chisel3/Data.scala729
-rw-r--r--core/src/main/scala/chisel3/Element.scala62
-rw-r--r--core/src/main/scala/chisel3/Mem.scala216
-rw-r--r--core/src/main/scala/chisel3/Module.scala405
-rw-r--r--core/src/main/scala/chisel3/ModuleAspect.scala26
-rw-r--r--core/src/main/scala/chisel3/MultiClock.scala70
-rw-r--r--core/src/main/scala/chisel3/Mux.scala50
-rw-r--r--core/src/main/scala/chisel3/Num.scala308
-rw-r--r--core/src/main/scala/chisel3/Printable.scala178
-rw-r--r--core/src/main/scala/chisel3/Printf.scala102
-rw-r--r--core/src/main/scala/chisel3/RawModule.scala233
-rw-r--r--core/src/main/scala/chisel3/Reg.scala195
-rw-r--r--core/src/main/scala/chisel3/SIntFactory.scala25
-rw-r--r--core/src/main/scala/chisel3/SeqUtils.scala128
-rw-r--r--core/src/main/scala/chisel3/StrongEnum.scala343
-rw-r--r--core/src/main/scala/chisel3/UIntFactory.scala47
-rw-r--r--core/src/main/scala/chisel3/When.scala85
-rw-r--r--core/src/main/scala/chisel3/aop/Aspect.scala40
-rw-r--r--core/src/main/scala/chisel3/core/package.scala288
-rw-r--r--core/src/main/scala/chisel3/dontTouch.scala37
-rw-r--r--core/src/main/scala/chisel3/experimental/Analog.scala85
-rw-r--r--core/src/main/scala/chisel3/experimental/package.scala140
-rw-r--r--core/src/main/scala/chisel3/internal/BiConnect.scala333
-rw-r--r--core/src/main/scala/chisel3/internal/Binding.scala114
-rw-r--r--core/src/main/scala/chisel3/internal/Builder.scala452
-rw-r--r--core/src/main/scala/chisel3/internal/Error.scala213
-rw-r--r--core/src/main/scala/chisel3/internal/MonoConnect.scala264
-rw-r--r--core/src/main/scala/chisel3/internal/Namer.scala154
-rw-r--r--core/src/main/scala/chisel3/internal/SourceInfo.scala61
-rw-r--r--core/src/main/scala/chisel3/internal/firrtl/Converter.scala275
-rw-r--r--core/src/main/scala/chisel3/internal/firrtl/IR.scala750
-rw-r--r--core/src/main/scala/chisel3/package.scala229
41 files changed, 10500 insertions, 0 deletions
diff --git a/core/src/main/scala/chisel3/Aggregate.scala b/core/src/main/scala/chisel3/Aggregate.scala
new file mode 100644
index 00000000..6c1e8dfb
--- /dev/null
+++ b/core/src/main/scala/chisel3/Aggregate.scala
@@ -0,0 +1,1016 @@
+// See LICENSE for license details.
+
+package chisel3
+
+import scala.collection.immutable.ListMap
+import scala.collection.mutable.{HashSet, LinkedHashMap}
+import scala.language.experimental.macros
+
+import chisel3.experimental.BaseModule
+import chisel3.experimental.BundleLiteralException
+import chisel3.experimental.EnumType
+import chisel3.internal._
+import chisel3.internal.Builder.pushCommand
+import chisel3.internal.firrtl._
+import chisel3.internal.sourceinfo._
+
+class AliasedAggregateFieldException(message: String) extends ChiselException(message)
+
+/** An abstract class for data types that solely consist of (are an aggregate
+ * of) other Data objects.
+ */
+sealed abstract class Aggregate extends Data {
+ private[chisel3] override def bind(target: Binding, parentDirection: SpecifiedDirection) { // scalastyle:ignore cyclomatic.complexity line.size.limit
+ binding = target
+
+ val resolvedDirection = SpecifiedDirection.fromParent(parentDirection, specifiedDirection)
+ val duplicates = getElements.groupBy(identity).collect { case (x, elts) if elts.size > 1 => x }
+ if (!duplicates.isEmpty) {
+ throw new AliasedAggregateFieldException(s"Aggregate $this contains aliased fields $duplicates")
+ }
+ for (child <- getElements) {
+ child.bind(ChildBinding(this), resolvedDirection)
+ }
+
+ // Check that children obey the directionality rules.
+ val childDirections = getElements.map(_.direction).toSet - ActualDirection.Empty
+ direction = ActualDirection.fromChildren(childDirections, resolvedDirection) match {
+ case Some(dir) => dir
+ case None =>
+ val childWithDirections = getElements zip getElements.map(_.direction)
+ throw MixedDirectionAggregateException(
+ s"Aggregate '$this' can't have elements that are both directioned and undirectioned: $childWithDirections")
+ }
+ }
+
+ override def litOption: Option[BigInt] = None // TODO implement me
+
+ /** Returns a Seq of the immediate contents of this Aggregate, in order.
+ */
+ def getElements: Seq[Data]
+
+ private[chisel3] def width: Width = getElements.map(_.width).foldLeft(0.W)(_ + _)
+ private[chisel3] def legacyConnect(that: Data)(implicit sourceInfo: SourceInfo): Unit = {
+ // If the source is a DontCare, generate a DefInvalid for the sink,
+ // otherwise, issue a Connect.
+ if (that == DontCare) {
+ pushCommand(DefInvalid(sourceInfo, Node(this)))
+ } else {
+ pushCommand(BulkConnect(sourceInfo, Node(this), Node(that)))
+ }
+ }
+
+ override def do_asUInt(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): UInt = {
+ SeqUtils.do_asUInt(flatten.map(_.asUInt()))
+ }
+ private[chisel3] override def connectFromBits(that: Bits)(implicit sourceInfo: SourceInfo,
+ compileOptions: CompileOptions): Unit = {
+ var i = 0
+ val bits = if (that.isLit) that else WireDefault(UInt(this.width), that) // handles width padding
+ for (x <- flatten) {
+ val fieldWidth = x.getWidth
+ if (fieldWidth > 0) {
+ x.connectFromBits(bits(i + fieldWidth - 1, i))
+ i += fieldWidth
+ } else {
+ // There's a zero-width field in this bundle.
+ // Zero-width fields can't really be assigned to, but the frontend complains if there are uninitialized fields,
+ // so we assign it to DontCare. We can't use connectFromBits() on DontCare, so use := instead.
+ x := DontCare
+ }
+ }
+ }
+}
+
+trait VecFactory extends SourceInfoDoc {
+ /** 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)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Vec[T] = {
+ if (compileOptions.declaredTypeMustBeUnbound) {
+ requireIsChiselType(gen, "vec type")
+ }
+ new Vec(gen.cloneTypeFull, n)
+ }
+
+ /** Truncate an index to implement modulo-power-of-2 addressing. */
+ private[chisel3] def truncateIndex(idx: UInt, n: BigInt)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): UInt = { // scalastyle:ignore line.size.limit
+ // scalastyle:off if.brace
+ val w = (n-1).bitLength
+ if (n <= 1) 0.U
+ else if (idx.width.known && idx.width.get <= w) idx
+ else if (idx.width.known) idx(w-1,0)
+ else (idx | 0.U(w.W))(w-1,0)
+ // scalastyle:on if.brace
+ }
+}
+
+// scalastyle:off line.size.limit
+/** A vector (array) of [[Data]] elements. Provides hardware versions of various
+ * collection transformation functions found in software array implementations.
+ *
+ * Careful consideration should be given over the use of [[Vec]] vs
+ * [[scala.collection.immutable.Seq Seq]] or some other Scala collection. In general [[Vec]] only
+ * needs to be used when there is a need to express the hardware collection in a [[Reg]] or IO
+ * [[Bundle]] or when access to elements of the array is indexed via a hardware signal.
+ *
+ * Example of indexing into a [[Vec]] using a hardware address and where the [[Vec]] is defined in
+ * an IO [[Bundle]]
+ *
+ * {{{
+ * val io = IO(new Bundle {
+ * val in = Input(Vec(20, UInt(16.W)))
+ * val addr = Input(UInt(5.W))
+ * val out = Output(UInt(16.W))
+ * })
+ * io.out := io.in(io.addr)
+ * }}}
+ *
+ * @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)
+ * - Vecs, unlike classes in Scala's collection library, are propagated intact to FIRRTL as a vector type, which may make debugging easier
+ */
+// scalastyle:on line.size.limit
+sealed class Vec[T <: Data] private[chisel3] (gen: => T, val length: Int)
+ extends Aggregate with VecLike[T] {
+ override def toString: String = {
+ val elementType = sample_element.cloneType
+ s"$elementType[$length]$bindingToString"
+ }
+
+ private[chisel3] override def typeEquivalent(that: Data): Boolean = that match {
+ case that: Vec[T] =>
+ this.length == that.length &&
+ (this.sample_element typeEquivalent that.sample_element)
+ case _ => false
+ }
+
+ private[chisel3] override def bind(target: Binding, parentDirection: SpecifiedDirection) {
+ binding = target
+
+ val resolvedDirection = SpecifiedDirection.fromParent(parentDirection, specifiedDirection)
+ sample_element.bind(SampleElementBinding(this), resolvedDirection)
+ for (child <- getElements) { // assume that all children are the same
+ child.bind(ChildBinding(this), resolvedDirection)
+ }
+
+ // Since all children are the same, we can just use the sample_element rather than all children
+ // .get is safe because None means mixed directions, we only pass 1 so that's not possible
+ direction = ActualDirection.fromChildren(Set(sample_element.direction), resolvedDirection).get
+ }
+
+ // 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 lazy val self: Seq[T] = {
+ val _self = Vector.fill(length)(gen)
+ for ((elt, i) <- _self.zipWithIndex)
+ elt.setRef(this, i)
+ _self
+ }
+
+ /**
+ * sample_element 'tracks' all changes to the elements.
+ * 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[chisel3] 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 override 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, moduleCompileOptions: CompileOptions): Unit = {
+ if (this.length != that.length) {
+ Builder.error("Vec and Seq being bulk connected have different lengths!")
+ }
+ for ((a, b) <- this zip that)
+ a <> b
+ }
+
+ // TODO: eliminate once assign(Seq) isn't ambiguous with assign(Data) since Vec extends Seq and Data
+ def <> (that: Vec[T])(implicit sourceInfo: SourceInfo, moduleCompileOptions: CompileOptions): Unit = this bulkConnect that.asInstanceOf[Data] // scalastyle:ignore line.size.limit
+
+ /** Strong bulk connect, assigning elements in this Vec from elements in a Seq.
+ *
+ * @note the length of this Vec must match the length of the input Seq
+ */
+ def := (that: Seq[T])(implicit sourceInfo: SourceInfo, moduleCompileOptions: CompileOptions): Unit = {
+ require(this.length == that.length, s"Cannot assign to a Vec of length ${this.length} from a Seq of different length ${that.length}")
+ for ((a, b) <- this zip that)
+ a := b
+ }
+
+ // TODO: eliminate once assign(Seq) isn't ambiguous with assign(Data) since Vec extends Seq and Data
+ def := (that: Vec[T])(implicit sourceInfo: SourceInfo, moduleCompileOptions: CompileOptions): Unit = this connect that
+
+ /** Creates a dynamically indexed read or write accessor into the array.
+ */
+ override def apply(p: UInt): T = macro CompileOptionsTransform.pArg
+
+ /** @group SourceInfoTransformMacro */
+ def do_apply(p: UInt)(implicit compileOptions: CompileOptions): T = {
+ requireIsHardware(this, "vec")
+ requireIsHardware(p, "vec index")
+ val port = gen
+
+ // Reconstruct the resolvedDirection (in Aggregate.bind), since it's not stored.
+ // It may not be exactly equal to that value, but the results are the same.
+ val reconstructedResolvedDirection = direction match {
+ case ActualDirection.Input => SpecifiedDirection.Input
+ case ActualDirection.Output => SpecifiedDirection.Output
+ case ActualDirection.Bidirectional(ActualDirection.Default) | ActualDirection.Unspecified =>
+ SpecifiedDirection.Unspecified
+ case ActualDirection.Bidirectional(ActualDirection.Flipped) => SpecifiedDirection.Flip
+ }
+ // TODO port technically isn't directly child of this data structure, but the result of some
+ // muxes / demuxes. However, this does make access consistent with the top-level bindings.
+ // Perhaps there's a cleaner way of accomplishing this...
+ port.bind(ChildBinding(this), reconstructedResolvedDirection)
+
+ val i = Vec.truncateIndex(p, length)(UnlocatableSourceInfo, compileOptions)
+ port.setRef(this, i)
+
+ port
+ }
+
+ /** Creates a statically indexed read or write accessor into the array.
+ */
+ def apply(idx: Int): T = self(idx)
+
+ override def cloneType: this.type = {
+ new Vec(gen.cloneTypeFull, length).asInstanceOf[this.type]
+ }
+
+ override def getElements: Seq[Data] =
+ (0 until length).map(apply(_))
+
+ /** Default "pretty-print" implementation
+ * Analogous to printing a Seq
+ * Results in "Vec(elt0, elt1, ...)"
+ */
+ def toPrintable: Printable = {
+ // scalastyle:off if.brace
+ val elts =
+ if (length == 0) List.empty[Printable]
+ else self flatMap (e => List(e.toPrintable, PString(", "))) dropRight 1
+ // scalastyle:on if.brace
+ PString("Vec(") + Printables(elts) + PString(")")
+ }
+
+ /** A reduce operation in a tree like structure instead of sequentially
+ * @example An adder tree
+ * {{{
+ * val sumOut = inputNums.reduceTree((a: T, b: T) => (a + b))
+ * }}}
+ */
+ def reduceTree(redOp: (T, T) => T): T = macro VecTransform.reduceTreeDefault
+
+ /** A reduce operation in a tree like structure instead of sequentially
+ * @example A pipelined adder tree
+ * {{{
+ * val sumOut = inputNums.reduceTree(
+ * (a: T, b: T) => RegNext(a + b),
+ * (a: T) => RegNext(a)
+ * )
+ * }}}
+ */
+ def reduceTree(redOp: (T, T) => T, layerOp: (T) => T): T = macro VecTransform.reduceTree
+
+ def do_reduceTree(redOp: (T, T) => T, layerOp: (T) => T = (x: T) => x)
+ (implicit sourceInfo: SourceInfo, compileOptions: CompileOptions) : T = {
+ require(!isEmpty, "Cannot apply reduction on a vec of size 0")
+ var curLayer = this
+ while (curLayer.length > 1) {
+ curLayer = VecInit(curLayer.grouped(2).map( x =>
+ if (x.length == 1) layerOp(x(0)) else redOp(x(0), x(1))
+ ).toSeq)
+ }
+ curLayer(0)
+ }
+}
+
+object VecInit extends SourceInfoDoc {
+ /** 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
+
+ /** @group SourceInfoTransformMacro */
+ def do_apply[T <: Data](elts: Seq[T])(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): 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.
+
+ // Check that types are homogeneous. Width mismatch for Elements is safe.
+ require(!elts.isEmpty)
+ elts.foreach(requireIsHardware(_, "vec element"))
+
+ val vec = Wire(Vec(elts.length, cloneSupertype(elts, "Vec")))
+
+ // TODO: try to remove the logic for this mess
+ elts.head.direction match {
+ case ActualDirection.Input | ActualDirection.Output | ActualDirection.Unspecified =>
+ // When internal wires are involved, driver / sink must be specified explicitly, otherwise
+ // the system is unable to infer which is driver / sink
+ (vec zip elts).foreach(x => x._1 := x._2)
+ case ActualDirection.Bidirectional(_) =>
+ // For bidirectional, must issue a bulk connect so subelements are resolved correctly.
+ // Bulk connecting two wires may not succeed because Chisel frontend does not infer
+ // directions.
+ (vec zip elts).foreach(x => x._1 <> x._2)
+ }
+ 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
+
+ /** @group SourceInfoTransformMacro */
+ def do_apply[T <: Data](elt0: T, elts: T*)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): 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
+
+ /** @group SourceInfoTransformMacro */
+ def do_tabulate[T <: Data](n: Int)(gen: (Int) => T)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Vec[T] = // scalastyle:ignore line.size.limit
+ apply((0 until n).map(i => gen(i)))
+}
+
+/** A trait for [[Vec]]s containing common hardware generators for collection
+ * operations.
+ */
+trait VecLike[T <: Data] extends collection.IndexedSeq[T] with HasId with SourceInfoDoc {
+ def apply(p: UInt): T = macro CompileOptionsTransform.pArg
+
+ /** @group SourceInfoTransformMacro */
+ def do_apply(p: UInt)(implicit compileOptions: CompileOptions): 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)
+
+ /** Outputs true if p outputs true for every element.
+ */
+ def forall(p: T => Bool): Bool = macro SourceInfoTransform.pArg
+
+ /** @group SourceInfoTransformMacro */
+ def do_forall(p: T => Bool)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Bool =
+ (this map p).fold(true.B)(_ && _)
+
+ /** Outputs true if p outputs true for at least one element.
+ */
+ def exists(p: T => Bool): Bool = macro SourceInfoTransform.pArg
+
+ /** @group SourceInfoTransformMacro */
+ def do_exists(p: T => Bool)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Bool =
+ (this map p).fold(false.B)(_ || _)
+
+ /** 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
+
+ /** @group SourceInfoTransformMacro */
+ def do_contains(x: T)(implicit sourceInfo: SourceInfo, ev: T <:< UInt, compileOptions: CompileOptions): Bool =
+ this.exists(_ === x)
+
+ /** Outputs the number of elements for which p is true.
+ */
+ def count(p: T => Bool): UInt = macro SourceInfoTransform.pArg
+
+ /** @group SourceInfoTransformMacro */
+ def do_count(p: T => Bool)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): 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 => i.asUInt)
+
+ /** Outputs the index of the first element for which p outputs true.
+ */
+ def indexWhere(p: T => Bool): UInt = macro SourceInfoTransform.pArg
+
+ /** @group SourceInfoTransformMacro */
+ def do_indexWhere(p: T => Bool)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): 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
+
+ /** @group SourceInfoTransformMacro */
+ def do_lastIndexWhere(p: T => Bool)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): 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
+
+ /** @group SourceInfoTransformMacro */
+ def do_onlyIndexWhere(p: T => Bool)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): UInt =
+ SeqUtils.oneHotMux(indexWhereHelper(p))
+}
+
+/** Base class for Aggregates based on key values pairs of String and Data
+ *
+ * Record should only be extended by libraries and fairly sophisticated generators.
+ * RTL writers should use [[Bundle]]. See [[Record#elements]] for an example.
+ */
+abstract class Record(private[chisel3] implicit val compileOptions: CompileOptions) extends Aggregate {
+ private[chisel3] override def bind(target: Binding, parentDirection: SpecifiedDirection): Unit = {
+ try {
+ super.bind(target, parentDirection)
+ } catch { // nasty compatibility mode shim, where anything flies
+ case e: MixedDirectionAggregateException if !compileOptions.dontAssumeDirectionality =>
+ val resolvedDirection = SpecifiedDirection.fromParent(parentDirection, specifiedDirection)
+ direction = resolvedDirection match {
+ case SpecifiedDirection.Unspecified => ActualDirection.Bidirectional(ActualDirection.Default)
+ case SpecifiedDirection.Flip => ActualDirection.Bidirectional(ActualDirection.Flipped)
+ case _ => ActualDirection.Bidirectional(ActualDirection.Default)
+ }
+ }
+ }
+
+ /** Creates a Bundle literal of this type with specified values. this must be a chisel type.
+ *
+ * @param elems literal values, specified as a pair of the Bundle field to the literal value.
+ * The Bundle field is specified as a function from an object of this type to the field.
+ * Fields that aren't initialized to DontCare, and assignment to a wire will overwrite any
+ * existing value with DontCare.
+ * @return a Bundle literal of this type with subelement values specified
+ *
+ * @example {{{
+ * class MyBundle extends Bundle {
+ * val a = UInt(8.W)
+ * val b = Bool()
+ * }
+ *
+ * (mew MyBundle).Lit(
+ * _.a -> 42.U,
+ * _.b -> true.B
+ * )
+ * }}}
+ */
+ private[chisel3] def _makeLit(elems: (this.type => (Data, Data))*): this.type = { // scalastyle:ignore line.size.limit method.length method.name cyclomatic.complexity
+ // Returns pairs of all fields, element-level and containers, in a Record and their path names
+ def getRecursiveFields(data: Data, path: String): Seq[(Data, String)] = data match {
+ case data: Record => data.elements.map { case (fieldName, fieldData) =>
+ getRecursiveFields(fieldData, s"$path.$fieldName")
+ }.fold(Seq(data -> path)) { _ ++ _ }
+ case data => Seq(data -> path) // we don't support or recurse into other Aggregate types here
+ }
+
+ // Returns pairs of corresponding fields between two Records of the same type
+ def getMatchedFields(x: Data, y: Data): Seq[(Data, Data)] = (x, y) match {
+ case (x: Element, y: Element) =>
+ require(x typeEquivalent y)
+ Seq(x -> y)
+ case (x: Record, y: Record) =>
+ (x.elements zip y.elements).map { case ((xName, xElt), (yName, yElt)) =>
+ require(xName == yName) // assume fields returned in same, deterministic order
+ getMatchedFields(xElt, yElt)
+ }.fold(Seq(x -> y)) { _ ++ _ }
+ }
+
+ requireIsChiselType(this, "bundle literal constructor model")
+ val clone = cloneType
+ val cloneFields = getRecursiveFields(clone, "(bundle root)").toMap
+
+ // Create the Bundle literal binding from litargs of arguments
+ val bundleLitMap = elems.map { fn => fn(clone) }.flatMap { case (field, value) =>
+ val fieldName = cloneFields.getOrElse(field,
+ throw new BundleLiteralException(s"field $field (with value $value) is not a field," +
+ s" ensure the field is specified as a function returning a field on an object of class ${this.getClass}," +
+ s" eg '_.a' to select hypothetical bundle field 'a'")
+ )
+ val valueBinding = value.topBindingOpt match {
+ case Some(litBinding: LitBinding) => litBinding
+ case _ => throw new BundleLiteralException(s"field $fieldName specified with non-literal value $value")
+ }
+
+ field match { // Get the litArg(s) for this field
+ case field: Bits =>
+ if (field.getClass != value.getClass) { // TODO typeEquivalent is too strict because it checks width
+ throw new BundleLiteralException(s"Field $fieldName $field specified with non-type-equivalent value $value")
+ }
+ val litArg = valueBinding match {
+ case ElementLitBinding(litArg) => litArg
+ case BundleLitBinding(litMap) => litMap.getOrElse(value,
+ throw new BundleLiteralException(s"Field $fieldName specified with unspecified value"))
+ }
+ Seq(field -> litArg)
+ case field: Record =>
+ if (!(field typeEquivalent value)) {
+ throw new BundleLiteralException(s"field $fieldName $field specified with non-type-equivalent value $value")
+ }
+ // Copy the source BundleLitBinding with fields (keys) remapped to the clone
+ val remap = getMatchedFields(value, field).toMap
+ value.topBinding.asInstanceOf[BundleLitBinding].litMap.map { case (valueField, valueValue) =>
+ remap(valueField) -> valueValue
+ }
+ case field: EnumType => {
+ if (!(field typeEquivalent value)) {
+ throw new BundleLiteralException(s"field $fieldName $field specified with non-type-equivalent enum value $value")
+ }
+ val litArg = valueBinding match {
+ case ElementLitBinding(litArg) => litArg
+ }
+ Seq(field -> litArg)
+ }
+ case _ => throw new BundleLiteralException(s"unsupported field $fieldName of type $field")
+ }
+ } // don't convert to a Map yet to preserve duplicate keys
+ val duplicates = bundleLitMap.map(_._1).groupBy(identity).collect { case (x, elts) if elts.size > 1 => x }
+ if (!duplicates.isEmpty) {
+ val duplicateNames = duplicates.map(cloneFields(_)).mkString(", ")
+ throw new BundleLiteralException(s"duplicate fields $duplicateNames in Bundle literal constructor")
+ }
+ clone.bind(BundleLitBinding(bundleLitMap.toMap))
+ clone
+ }
+
+ /** The collection of [[Data]]
+ *
+ * This underlying datastructure is a ListMap because the elements must
+ * remain ordered for serialization/deserialization. Elements added later
+ * are higher order when serialized (this is similar to [[Vec]]). For example:
+ * {{{
+ * // Assume we have some type MyRecord that creates a Record from the ListMap
+ * val record = MyRecord(ListMap("fizz" -> UInt(16.W), "buzz" -> UInt(16.W)))
+ * // "buzz" is higher order because it was added later than "fizz"
+ * record("fizz") := "hdead".U
+ * record("buzz") := "hbeef".U
+ * val uint = record.asUInt
+ * assert(uint === "hbeefdead".U) // This will pass
+ * }}}
+ */
+ override def toString: String = {
+ val bindingString = topBindingOpt match {
+ case Some(BundleLitBinding(_)) =>
+ val contents = elements.toList.reverse.map { case (name, data) =>
+ s"$name=$data"
+ }.mkString(", ")
+ s"($contents)"
+ case _ => bindingToString
+ }
+ s"$className$bindingString"
+ }
+
+ val elements: ListMap[String, Data]
+
+ /** Name for Pretty Printing */
+ def className: String = this.getClass.getSimpleName
+
+ private[chisel3] override def typeEquivalent(that: Data): Boolean = that match {
+ case that: Record =>
+ this.getClass == that.getClass &&
+ this.elements.size == that.elements.size &&
+ this.elements.forall{case (name, model) =>
+ that.elements.contains(name) &&
+ (that.elements(name) typeEquivalent model)}
+ case _ => false
+ }
+
+ // NOTE: This sets up dependent references, it can be done before closing the Module
+ private[chisel3] override def _onModuleClose: Unit = { // scalastyle:ignore method.name
+ // Since Bundle names this via reflection, it is impossible for two elements to have the same
+ // identifier; however, Namespace sanitizes identifiers to make them legal for Firrtl/Verilog
+ // which can cause collisions
+ val _namespace = Namespace.empty
+ for ((name, elt) <- elements) { elt.setRef(this, _namespace.name(name, leadingDigitOk=true)) }
+ }
+
+ private[chisel3] final def allElements: Seq[Element] = elements.toIndexedSeq.flatMap(_._2.allElements)
+
+ override def getElements: Seq[Data] = elements.toIndexedSeq.map(_._2)
+
+ // Helper because Bundle elements are reversed before printing
+ private[chisel3] def toPrintableHelper(elts: Seq[(String, Data)]): Printable = {
+ // scalastyle:off if.brace
+ val xs =
+ if (elts.isEmpty) List.empty[Printable] // special case because of dropRight below
+ else elts flatMap { case (name, data) =>
+ List(PString(s"$name -> "), data.toPrintable, PString(", "))
+ } dropRight 1 // Remove trailing ", "
+ // scalastyle:on if.brace
+ PString(s"$className(") + Printables(xs) + PString(")")
+ }
+ /** Default "pretty-print" implementation
+ * Analogous to printing a Map
+ * Results in "`\$className(elt0.name -> elt0.value, ...)`"
+ */
+ def toPrintable: Printable = toPrintableHelper(elements.toList)
+}
+
+/**
+ * Mix-in for Bundles that have arbitrary Seqs of Chisel types that aren't
+ * involved in hardware construction.
+ *
+ * Used to avoid raising an error/exception when a Seq is a public member of the
+ * bundle.
+ * This is useful if we those public Seq fields in the Bundle are unrelated to
+ * hardware construction.
+ */
+trait IgnoreSeqInBundle {
+ this: Bundle =>
+
+ override def ignoreSeq: Boolean = true
+}
+
+class AutoClonetypeException(message: String) extends ChiselException(message)
+
+package experimental {
+
+ class BundleLiteralException(message: String) extends ChiselException(message)
+
+}
+
+/** 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.
+ *
+ * Example of an anonymous IO bundle
+ * {{{
+ * class MyModule extends Module {
+ * val io = IO(new Bundle {
+ * val in = Input(UInt(64.W))
+ * val out = Output(SInt(128.W))
+ * })
+ * }
+ * }}}
+ *
+ * Or as a named class
+ * {{{
+ * class Packet extends Bundle {
+ * val header = UInt(16.W)
+ * val addr = UInt(16.W)
+ * val data = UInt(32.W)
+ * }
+ * class MyModule extends Module {
+ * val io = IO(new Bundle {
+ * val inPacket = Input(new Packet)
+ * val outPacket = Output(new Packet)
+ * })
+ * val reg = Reg(new Packet)
+ * reg <> io.inPacket
+ * io.outPacket <> reg
+ * }
+ * }}}
+ */
+abstract class Bundle(implicit compileOptions: CompileOptions) extends Record {
+ override def className: String = this.getClass.getSimpleName match {
+ case name if name.startsWith("$anon$") => "AnonymousBundle" // fallback for anonymous Bundle case
+ case "" => "AnonymousBundle" // ditto, but on other platforms
+ case name => name
+ }
+ /** The collection of [[Data]]
+ *
+ * Elements defined earlier in the Bundle are higher order upon
+ * serialization. For example:
+ * @example
+ * {{{
+ * class MyBundle extends Bundle {
+ * val foo = UInt(16.W)
+ * val bar = UInt(16.W)
+ * }
+ * // Note that foo is higher order because its defined earlier in the Bundle
+ * val bundle = Wire(new MyBundle)
+ * bundle.foo := 0x1234.U
+ * bundle.bar := 0x5678.U
+ * val uint = bundle.asUInt
+ * assert(uint === "h12345678".U) // This will pass
+ * }}}
+ */
+ final lazy val elements: ListMap[String, Data] = {
+ val nameMap = LinkedHashMap[String, Data]()
+ for (m <- getPublicFields(classOf[Bundle])) {
+ getBundleField(m) match {
+ case Some(d: Data) =>
+ if (nameMap contains m.getName) {
+ require(nameMap(m.getName) eq d)
+ } else {
+ nameMap(m.getName) = d
+ }
+ case None =>
+ if (!ignoreSeq) {
+ m.invoke(this) match {
+ case s: scala.collection.Seq[Any] if s.nonEmpty => s.head match {
+ // Ignore empty Seq()
+ case d: Data => throwException("Public Seq members cannot be used to define Bundle elements " +
+ s"(found public Seq member '${m.getName}'). " +
+ "Either use a Vec if all elements are of the same type, or MixedVec if the elements " +
+ "are of different types. If this Seq member is not intended to construct RTL, mix in the trait " +
+ "IgnoreSeqInBundle.")
+ case _ => // don't care about non-Data Seq
+ }
+ case _ => // not a Seq
+ }
+ }
+ }
+ }
+ ListMap(nameMap.toSeq sortWith { case ((an, a), (bn, b)) => (a._id > b._id) || ((a eq b) && (an > bn)) }: _*)
+ // scalastyle:ignore method.length
+ }
+
+ /**
+ * Overridden by [[IgnoreSeqInBundle]] to allow arbitrary Seqs of Chisel elements.
+ */
+ def ignoreSeq: Boolean = false
+
+ /** 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] = m.invoke(this) match {
+ case d: Data => Some(d)
+ case Some(d: Data) => Some(d)
+ case _ => None
+ }
+
+ // Memoize the outer instance for autoclonetype, especially where this is context-dependent
+ // (like the outer module or enclosing Bundles).
+ private var _outerInst: Option[Object] = None
+
+ // For autoclonetype, record possible candidates for outer instance.
+ // _outerInst should always take precedence, since it should be propagated from the original
+ // object which has the most accurate context.
+ private val _containingModule: Option[BaseModule] = Builder.currentModule
+ private val _containingBundles: Seq[Bundle] = Builder.updateBundleStack(this)
+
+ override def cloneType : this.type = { // scalastyle:ignore cyclomatic.complexity method.length
+ // This attempts to infer constructor and arguments to clone this Bundle subtype without
+ // requiring the user explicitly overriding cloneType.
+ import scala.language.existentials
+ import scala.reflect.runtime.universe._
+
+ val clazz = this.getClass
+
+ def autoClonetypeError(desc: String): Nothing = {
+ throw new AutoClonetypeException(s"Unable to automatically infer cloneType on $clazz: $desc")
+ }
+
+ def validateClone(clone: Bundle, equivDiagnostic: String): Unit = {
+ if (!clone.typeEquivalent(this)) {
+ autoClonetypeError(s"Automatically cloned $clone not type-equivalent to base $this. " + equivDiagnostic)
+ }
+
+ for ((name, field) <- elements) {
+ if (clone.elements(name) eq field) {
+ autoClonetypeError(s"Automatically cloned $clone has field $name aliased with base $this." +
+ " In the future, this can be solved by wrapping the field in Field(...)," +
+ " see https://github.com/freechipsproject/chisel3/pull/909." +
+ " For now, ensure Chisel types used in the Bundle definition are passed through constructor arguments," +
+ " or wrapped in Input(...), Output(...), or Flipped(...) if appropriate.")
+ }
+ }
+ }
+
+ val mirror = runtimeMirror(clazz.getClassLoader)
+ val classSymbolOption = try {
+ Some(mirror.reflect(this).symbol)
+ } catch {
+ case e: scala.reflect.internal.Symbols#CyclicReference => None // Workaround for a scala bug
+ }
+
+ val enclosingClassOption = (clazz.getEnclosingClass, classSymbolOption) match {
+ case (null, _) => None
+ case (_, Some(classSymbol)) if classSymbol.isStatic => None // allows support for members of companion objects
+ case (outerClass, _) => Some(outerClass)
+ }
+
+ // For compatibility with pre-3.1, where null is tried as an argument to the constructor.
+ // This stores potential error messages which may be used later.
+ var outerClassError: Option[String] = None
+
+ // Check if this is an inner class, and if so, try to get the outer instance
+ val outerClassInstance = enclosingClassOption.map { outerClass =>
+ def canAssignOuterClass(x: Object) = outerClass.isAssignableFrom(x.getClass)
+
+ val outerInstance = _outerInst match {
+ case Some(outerInstance) => outerInstance // use _outerInst if defined
+ case None => // determine outer instance if not already recorded
+ try {
+ // Prefer this if it works, but doesn't work in all cases, namely anonymous inner Bundles
+ val outer = clazz.getDeclaredField("$outer").get(this)
+ _outerInst = Some(outer)
+ outer
+ } catch {
+ case (_: NoSuchFieldException | _: IllegalAccessException) =>
+ // Fallback using guesses based on common patterns
+ val allOuterCandidates = Seq(
+ _containingModule.toSeq,
+ _containingBundles
+ ).flatten.distinct
+ allOuterCandidates.filter(canAssignOuterClass(_)) match {
+ case outer :: Nil =>
+ _outerInst = Some(outer) // record the guess for future use
+ outer
+ case Nil => // TODO: replace with fatal autoClonetypeError once compatibility period is dropped
+ outerClassError = Some(s"Unable to determine instance of outer class $outerClass," +
+ s" no candidates assignable to outer class types; examined $allOuterCandidates")
+ null
+ case candidates => // TODO: replace with fatal autoClonetypeError once compatibility period is dropped
+ outerClassError = Some(s"Unable to determine instance of outer class $outerClass," +
+ s" multiple possible candidates $candidates assignable to outer class type")
+ null
+ }
+ }
+ }
+ (outerClass, outerInstance)
+ }
+
+ // If possible (constructor with no arguments), try Java reflection first
+ // This handles two cases that Scala reflection doesn't:
+ // 1. getting the ClassSymbol of a class with an anonymous outer class fails with a
+ // CyclicReference exception
+ // 2. invoking the constructor of an anonymous inner class seems broken (it expects the outer
+ // class as an argument, but fails because the number of arguments passed in is incorrect)
+ if (clazz.getConstructors.size == 1) {
+ var ctor = clazz.getConstructors.head
+ val argTypes = ctor.getParameterTypes.toList
+ val clone = (argTypes, outerClassInstance) match {
+ case (Nil, None) => // no arguments, no outer class, invoke constructor directly
+ Some(ctor.newInstance().asInstanceOf[this.type])
+ case (argType :: Nil, Some((_, outerInstance))) =>
+ if (outerInstance == null) {
+ Builder.deprecated(s"chisel3.1 autoclonetype failed, falling back to 3.0 behavior using null as the outer instance." + // scalastyle:ignore line.size.limit
+ s" Autoclonetype failure reason: ${outerClassError.get}",
+ Some(s"$clazz"))
+ Some(ctor.newInstance(outerInstance).asInstanceOf[this.type])
+ } else if (argType isAssignableFrom outerInstance.getClass) {
+ Some(ctor.newInstance(outerInstance).asInstanceOf[this.type])
+ } else {
+ None
+ }
+ case _ => None
+
+ }
+ clone match {
+ case Some(clone) =>
+ clone._outerInst = this._outerInst
+ validateClone(clone, "Constructor argument values were not inferred, ensure constructor is deterministic.")
+ return clone.asInstanceOf[this.type]
+ case None =>
+ }
+ }
+
+ // Get constructor parameters and accessible fields
+ val classSymbol = classSymbolOption.getOrElse(autoClonetypeError(s"scala reflection failed." +
+ " This is known to occur with inner classes on anonymous outer classes." +
+ " In those cases, autoclonetype only works with no-argument constructors, or you can define a custom cloneType.")) // scalastyle:ignore line.size.limit
+
+ val decls = classSymbol.typeSignature.decls
+ val ctors = decls.collect { case meth: MethodSymbol if meth.isConstructor => meth }
+ if (ctors.size != 1) {
+ autoClonetypeError(s"found multiple constructors ($ctors)." +
+ " Either remove all but the default constructor, or define a custom cloneType method.")
+ }
+ val ctor = ctors.head
+ val ctorParamss = ctor.paramLists
+ val ctorParams = ctorParamss match {
+ case Nil => List()
+ case ctorParams :: Nil => ctorParams
+ case ctorParams :: ctorImplicits :: Nil => ctorParams ++ ctorImplicits
+ case _ => autoClonetypeError(s"internal error, unexpected ctorParamss = $ctorParamss")
+ }
+ val ctorParamsNames = ctorParams.map(_.name.toString)
+
+ // Special case for anonymous inner classes: their constructor consists of just the outer class reference
+ // Scala reflection on anonymous inner class constructors seems broken
+ if (ctorParams.size == 1 && outerClassInstance.isDefined &&
+ ctorParams.head.typeSignature == mirror.classSymbol(outerClassInstance.get._1).toType) {
+ // Fall back onto Java reflection
+ val ctors = clazz.getConstructors
+ require(ctors.size == 1) // should be consistent with Scala constructors
+ try {
+ val clone = ctors.head.newInstance(outerClassInstance.get._2).asInstanceOf[this.type]
+ clone._outerInst = this._outerInst
+
+ validateClone(clone, "Outer class instance was inferred, ensure constructor is deterministic.")
+ return clone
+ } catch {
+ case e @ (_: java.lang.reflect.InvocationTargetException | _: IllegalArgumentException) =>
+ autoClonetypeError(s"unexpected failure at constructor invocation, got $e.")
+ }
+ }
+
+ // Get all the class symbols up to (but not including) Bundle and get all the accessors.
+ // (each ClassSymbol's decls only includes those declared in the class itself)
+ val bundleClassSymbol = mirror.classSymbol(classOf[Bundle])
+ val superClassSymbols = classSymbol.baseClasses.takeWhile(_ != bundleClassSymbol)
+ val superClassDecls = superClassSymbols.map(_.typeSignature.decls).flatten
+ val accessors = superClassDecls.collect { case meth: MethodSymbol if meth.isParamAccessor => meth }
+
+ // Get constructor argument values
+ // Check that all ctor params are immutable and accessible. Immutability is required to avoid
+ // potential subtle bugs (like values changing after cloning).
+ // This also generates better error messages (all missing elements shown at once) instead of
+ // failing at the use site one at a time.
+ val accessorsName = accessors.filter(_.isStable).map(_.name.toString)
+ val paramsDiff = ctorParamsNames.toSet -- accessorsName.toSet
+ if (!paramsDiff.isEmpty) {
+ // scalastyle:off line.size.limit
+ autoClonetypeError(s"constructor has parameters (${paramsDiff.toList.sorted.mkString(", ")}) that are not both immutable and accessible." +
+ " Either make all parameters immutable and accessible (vals) so cloneType can be inferred, or define a custom cloneType method.")
+ // scalastyle:on line.size.limit
+ }
+
+ // Get all the argument values
+ val accessorsMap = accessors.map(accessor => accessor.name.toString -> accessor).toMap
+ val instanceReflect = mirror.reflect(this)
+ val ctorParamsNameVals = ctorParamsNames.map {
+ paramName => paramName -> instanceReflect.reflectMethod(accessorsMap(paramName)).apply()
+ }
+
+ // Opportunistic sanity check: ensure any arguments of type Data is not bound
+ // (which could lead to data conflicts, since it's likely the user didn't know to re-bind them).
+ // This is not guaranteed to catch all cases (for example, Data in Tuples or Iterables).
+ val boundDataParamNames = ctorParamsNameVals.collect {
+ case (paramName, paramVal: Data) if paramVal.topBindingOpt.isDefined => paramName
+ }
+ if (boundDataParamNames.nonEmpty) {
+ // scalastyle:off line.size.limit
+ autoClonetypeError(s"constructor parameters (${boundDataParamNames.sorted.mkString(", ")}) have values that are hardware types, which is likely to cause subtle errors." +
+ " Use chisel types instead: use the value before it is turned to a hardware type (with Wire(...), Reg(...), etc) or use chiselTypeOf(...) to extract the chisel type.")
+ // scalastyle:on line.size.limit
+ }
+
+ // Clone unbound parameters in case they are being used as bundle fields.
+ val ctorParamsVals = ctorParamsNameVals.map {
+ case (_, paramVal: Data) => paramVal.cloneTypeFull
+ case (_, paramVal) => paramVal
+ }
+
+ // Invoke ctor
+ val classMirror = outerClassInstance match {
+ case Some((_, null)) => autoClonetypeError(outerClassError.get) // deals with the null hack for 3.0 compatibility
+ case Some((_, outerInstance)) => mirror.reflect(outerInstance).reflectClass(classSymbol)
+ case _ => mirror.reflectClass(classSymbol)
+ }
+ val clone = classMirror.reflectConstructor(ctor).apply(ctorParamsVals:_*).asInstanceOf[this.type]
+ clone._outerInst = this._outerInst
+
+ validateClone(clone,
+ "Constructor argument values were inferred:" +
+ " ensure that variable names are consistent and have the same value throughout the constructor chain," +
+ " and that the constructor is deterministic."
+ )
+ clone
+ }
+
+ /** Default "pretty-print" implementation
+ * Analogous to printing a Map
+ * Results in "`Bundle(elt0.name -> elt0.value, ...)`"
+ * @note The order is reversed from the order of elements in order to print
+ * the fields in the order they were defined
+ */
+ override def toPrintable: Printable = toPrintableHelper(elements.toList.reverse)
+ // scalastyle:off method.length
+}
+// scalastyle:off file.size.limit
diff --git a/core/src/main/scala/chisel3/Annotation.scala b/core/src/main/scala/chisel3/Annotation.scala
new file mode 100644
index 00000000..e54b1bf9
--- /dev/null
+++ b/core/src/main/scala/chisel3/Annotation.scala
@@ -0,0 +1,94 @@
+// See LICENSE for license details.
+
+package chisel3.experimental
+
+import scala.language.existentials
+import chisel3.internal.{Builder, InstanceId, LegacyModule}
+import chisel3.{CompileOptions, Data}
+import firrtl.Transform
+import firrtl.annotations._
+import firrtl.options.Unserializable
+import firrtl.transforms.{DontTouchAnnotation, NoDedupAnnotation}
+
+/** Interface for Annotations in Chisel
+ *
+ * Defines a conversion to a corresponding FIRRTL Annotation
+ */
+trait ChiselAnnotation {
+ /** Conversion to FIRRTL Annotation */
+ def toFirrtl: Annotation
+}
+
+/** Mixin for [[ChiselAnnotation]] that instantiates an associated FIRRTL Transform when this Annotation is present
+ * during a run of
+ * [[Driver$.execute(args:Array[String],dut:()=>chisel3\.RawModule)* Driver.execute]].
+ * Automatic Transform instantiation is *not* supported when the Circuit and Annotations are serialized before invoking
+ * FIRRTL.
+ */
+trait RunFirrtlTransform extends ChiselAnnotation {
+ def transformClass: Class[_ <: Transform]
+}
+
+
+// This exists for implementation reasons, we don't want people using this type directly
+final case class ChiselLegacyAnnotation private[chisel3] (
+ component: InstanceId,
+ transformClass: Class[_ <: Transform],
+ value: String) extends ChiselAnnotation with RunFirrtlTransform {
+ def toFirrtl: Annotation = Annotation(component.toNamed, transformClass, value)
+}
+private[chisel3] object ChiselLegacyAnnotation
+
+object annotate { // scalastyle:ignore object.name
+ def apply(anno: ChiselAnnotation): Unit = {
+ Builder.annotations += anno
+ }
+}
+
+/** Marks that a module to be ignored in Dedup Transform in Firrtl pass
+ *
+ * @example {{{
+ * def fullAdder(a: UInt, b: UInt, myName: String): UInt = {
+ * val m = Module(new Module {
+ * val io = IO(new Bundle {
+ * val a = Input(UInt(32.W))
+ * val b = Input(UInt(32.W))
+ * val out = Output(UInt(32.W))
+ * })
+ * override def desiredName = "adder_" + myNname
+ * io.out := io.a + io.b
+ * })
+ * doNotDedup(m)
+ * m.io.a := a
+ * m.io.b := b
+ * m.io.out
+ * }
+ *
+ *class AdderTester extends Module
+ * with ConstantPropagationTest {
+ * val io = IO(new Bundle {
+ * val a = Input(UInt(32.W))
+ * val b = Input(UInt(32.W))
+ * val out = Output(Vec(2, UInt(32.W)))
+ * })
+ *
+ * io.out(0) := fullAdder(io.a, io.b, "mod1")
+ * io.out(1) := fullAdder(io.a, io.b, "mod2")
+ * }
+ * }}}
+ *
+ * @note Calling this on [[Data]] creates an annotation that Chisel emits to a separate annotations
+ * file. This file must be passed to FIRRTL independently of the `.fir` file. The execute methods
+ * in [[chisel3.Driver]] will pass the annotations to FIRRTL automatically.
+ */
+
+object doNotDedup { // scalastyle:ignore object.name
+ /** Marks a module to be ignored in Dedup Transform in Firrtl
+ *
+ * @param module The module to be marked
+ * @return Unmodified signal `module`
+ */
+ def apply[T <: LegacyModule](module: T)(implicit compileOptions: CompileOptions): Unit = {
+ annotate(new ChiselAnnotation { def toFirrtl = NoDedupAnnotation(module.toNamed) })
+ }
+}
diff --git a/core/src/main/scala/chisel3/Assert.scala b/core/src/main/scala/chisel3/Assert.scala
new file mode 100644
index 00000000..af58bce6
--- /dev/null
+++ b/core/src/main/scala/chisel3/Assert.scala
@@ -0,0 +1,92 @@
+// See LICENSE for license details.
+
+package chisel3
+
+import scala.reflect.macros.blackbox.Context
+import scala.language.experimental.macros
+
+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
+ * 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 format string to print when the assertion fires
+ * @param data optional bits to print in the message formatting
+ *
+ * @note See [[printf.apply(fmt:String* printf]] for format string documentation
+ * @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, data: Bits*)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Unit = macro apply_impl_msg_data // scalastyle:ignore line.size.limit
+ def apply(cond: Bool)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Unit = macro apply_impl
+
+ def apply_impl_msg_data(c: Context)(cond: c.Tree, message: c.Tree, data: c.Tree*)(sourceInfo: c.Tree, compileOptions: c.Tree): c.Tree = { // scalastyle:ignore line.size.limit
+ 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), ..$data)($sourceInfo, $compileOptions)"
+ }
+
+ def apply_impl(c: Context)(cond: c.Tree)(sourceInfo: c.Tree, compileOptions: 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, $compileOptions)"
+ }
+
+ def apply_impl_do(cond: Bool, line: String, message: Option[String], data: Bits*)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions) { // scalastyle:ignore line.size.limit
+ val escLine = line.replaceAll("%", "%%")
+ when (!(cond || Module.reset.asBool)) {
+ val fmt = message match {
+ case Some(msg) =>
+ s"Assertion failed: $msg\n at $escLine\n"
+ case None => s"Assertion failed\n at $escLine\n"
+ }
+ printf.printfWithoutReset(fmt, data:_*)
+ pushCommand(Stop(sourceInfo, Builder.forcedClock.ref, 1))
+ }
+ }
+
+ /** An elaboration-time assertion, otherwise the same as the above run-time
+ * assertion. */
+ def apply(cond: Boolean, message: => String) {
+ Predef.assert(cond, message)
+ }
+
+ /** A workaround for default-value overloading problems in Scala, just
+ * 'assert(cond, "")' */
+ def apply(cond: Boolean) {
+ Predef.assert(cond, "")
+ }
+}
+
+object stop { // scalastyle:ignore object.name
+ /** Terminate execution with a failure code. */
+ def apply(code: Int)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Unit = {
+ when (!Module.reset.asBool) {
+ pushCommand(Stop(sourceInfo, Builder.forcedClock.ref, code))
+ }
+ }
+
+ /** Terminate execution, indicating success. */
+ def apply()(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Unit = {
+ stop(0)
+ }
+}
diff --git a/core/src/main/scala/chisel3/Attach.scala b/core/src/main/scala/chisel3/Attach.scala
new file mode 100644
index 00000000..25c83d9a
--- /dev/null
+++ b/core/src/main/scala/chisel3/Attach.scala
@@ -0,0 +1,46 @@
+// See LICENSE for license details.
+
+package chisel3.experimental
+
+import chisel3.RawModule
+import chisel3.internal._
+import chisel3.internal.Builder.pushCommand
+import chisel3.internal.firrtl._
+import chisel3.internal.sourceinfo.SourceInfo
+
+object attach { // scalastyle:ignore object.name
+ // Exceptions that can be generated by attach
+ case class AttachException(message: String) extends ChiselException(message)
+ def ConditionalAttachException: AttachException = // scalastyle:ignore method.name
+ AttachException(": Conditional attach is not allowed!")
+
+ // Actual implementation
+ private[chisel3] def impl(elts: Seq[Analog], contextModule: RawModule)(implicit sourceInfo: SourceInfo): Unit = {
+ if (Builder.whenDepth != 0) throw ConditionalAttachException
+
+ // TODO Check that references are valid and can be attached
+
+ pushCommand(Attach(sourceInfo, elts.map(_.lref)))
+ }
+
+ /** Create an electrical connection between [[Analog]] components
+ *
+ * @param elts The components to attach
+ *
+ * @example
+ * {{{
+ * val a1 = Wire(Analog(32.W))
+ * val a2 = Wire(Analog(32.W))
+ * attach(a1, a2)
+ * }}}
+ */
+ def apply(elts: Analog*)(implicit sourceInfo: SourceInfo): Unit = {
+ try {
+ impl(elts, Builder.forcedUserModule)
+ } catch {
+ case AttachException(message) =>
+ throwException(elts.mkString("Attaching (", ", ", s") failed @$message"))
+ }
+ }
+}
+
diff --git a/core/src/main/scala/chisel3/Bits.scala b/core/src/main/scala/chisel3/Bits.scala
new file mode 100644
index 00000000..43c34d9d
--- /dev/null
+++ b/core/src/main/scala/chisel3/Bits.scala
@@ -0,0 +1,2289 @@
+// See LICENSE for license details.
+
+package chisel3
+
+import scala.language.experimental.macros
+
+import chisel3.experimental.{FixedPoint, Interval}
+import chisel3.internal._
+import chisel3.internal.Builder.pushOp
+import chisel3.internal.firrtl._
+import chisel3.internal.sourceinfo.{SourceInfo, SourceInfoTransform, SourceInfoWhiteboxTransform,
+ UIntTransform}
+import chisel3.internal.firrtl.PrimOp._
+import _root_.firrtl.{ir => firrtlir}
+import _root_.firrtl.{constraint => firrtlconstraint}
+
+// scalastyle:off method.name line.size.limit file.size.limit
+
+/** Exists to unify common interfaces of [[Bits]] and [[Reset]].
+ *
+ * @note This is a workaround because macros cannot override abstract methods.
+ */
+private[chisel3] sealed trait ToBoolable extends Element {
+
+ /** Casts this $coll to a [[Bool]]
+ *
+ * @note The width must be known and equal to 1
+ */
+ final def asBool(): Bool = macro SourceInfoWhiteboxTransform.noArg
+
+ /** @group SourceInfoTransformMacro */
+ def do_asBool(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Bool
+
+ /** Casts this $coll to a [[Bool]]
+ *
+ * @note The width must be known and equal to 1
+ */
+ final def toBool(): Bool = macro SourceInfoWhiteboxTransform.noArg
+
+ /** @group SourceInfoTransformMacro */
+ def do_toBool(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Bool
+}
+
+/** A data type for values represented by a single bitvector. This provides basic bitwise operations.
+ *
+ * @groupdesc Bitwise Bitwise hardware operators
+ * @define coll [[Bits]]
+ * @define sumWidthInt @note The width of the returned $coll is `width of this` + `that`.
+ * @define sumWidth @note The width of the returned $coll is `width of this` + `width of that`.
+ * @define unchangedWidth @note The width of the returned $coll is unchanged, i.e., the `width of this`.
+ */
+sealed abstract class Bits(private[chisel3] val width: Width) extends Element with ToBoolable { //scalastyle:off number.of.methods
+ // 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
+
+ // Only used for in a few cases, hopefully to be removed
+ private[chisel3] def cloneTypeWidth(width: Width): this.type
+
+ def cloneType: this.type = cloneTypeWidth(width)
+
+ /** Tail operator
+ *
+ * @param n the number of bits to remove
+ * @return This $coll with the `n` most significant bits removed.
+ * @group Bitwise
+ */
+ final def tail(n: Int): UInt = macro SourceInfoTransform.nArg
+
+ /** Head operator
+ *
+ * @param n the number of bits to take
+ * @return The `n` most significant bits of this $coll
+ * @group Bitwise
+ */
+ final def head(n: Int): UInt = macro SourceInfoTransform.nArg
+
+ /** @group SourceInfoTransformMacro */
+ def do_tail(n: Int)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): 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)
+ }
+
+ /** @group SourceInfoTransformMacro */
+ def do_head(n: Int)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): 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 $coll as a [[Bool]], statically addressed.
+ *
+ * @param x an index
+ * @return the specified bit
+ */
+ final def apply(x: BigInt): Bool = macro SourceInfoTransform.xArg
+
+ /** @group SourceInfoTransformMacro */
+ final def do_apply(x: BigInt)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Bool = {
+ if (x < 0) {
+ Builder.error(s"Negative bit indices are illegal (got $x)")
+ }
+ // This preserves old behavior while a more more consistent API is under debate
+ // See https://github.com/freechipsproject/chisel3/issues/867
+ litOption.map { value =>
+ (((value >> castToInt(x, "Index")) & 1) == 1).asBool
+ }.getOrElse {
+ requireIsHardware(this, "bits to be indexed")
+ pushOp(DefPrim(sourceInfo, Bool(), BitsExtractOp, this.ref, ILit(x), ILit(x)))
+ }
+ }
+
+ /** Returns the specified bit on this $coll as a [[Bool]], statically addressed.
+ *
+ * @param x an index
+ * @return the specified bit
+ * @note convenience method allowing direct use of [[scala.Int]] without implicits
+ */
+ final def apply(x: Int): Bool = macro SourceInfoTransform.xArg
+
+ /** @group SourceInfoTransformMacro */
+ final def do_apply(x: Int)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Bool = apply(BigInt(x))
+
+ /** Returns the specified bit on this wire as a [[Bool]], dynamically addressed.
+ *
+ * @param x a hardware component whose value will be used for dynamic addressing
+ * @return the specified bit
+ */
+ final def apply(x: UInt): Bool = macro SourceInfoTransform.xArg
+
+ /** @group SourceInfoTransformMacro */
+ final def do_apply(x: UInt)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Bool = {
+ val theBits = this >> x
+ theBits(0)
+ }
+
+ /** Returns a subset of bits on this $coll from `hi` to `lo` (inclusive), statically addressed.
+ *
+ * @example
+ * {{{
+ * myBits = 0x5 = 0b101
+ * myBits(1,0) => 0b01 // extracts the two least significant bits
+ * }}}
+ * @param x the high bit
+ * @param y the low bit
+ * @return a hardware component contain the requested bits
+ */
+ final def apply(x: Int, y: Int): UInt = macro SourceInfoTransform.xyArg
+
+ /** @group SourceInfoTransformMacro */
+ final def do_apply(x: Int, y: Int)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): UInt = {
+ if (x < y || y < 0) {
+ Builder.error(s"Invalid bit range ($x,$y)")
+ }
+ val w = x - y + 1
+ // This preserves old behavior while a more more consistent API is under debate
+ // See https://github.com/freechipsproject/chisel3/issues/867
+ litOption.map { value =>
+ ((value >> y) & ((BigInt(1) << w) - 1)).asUInt(w.W)
+ }.getOrElse {
+ requireIsHardware(this, "bits to be sliced")
+ 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?
+ /** Returns a subset of bits on this $coll from `hi` to `lo` (inclusive), statically addressed.
+ *
+ * @example
+ * {{{
+ * myBits = 0x5 = 0b101
+ * myBits(1,0) => 0b01 // extracts the two least significant bits
+ * }}}
+ * @param x the high bit
+ * @param y the low bit
+ * @return a hardware component contain the requested bits
+ */
+ final def apply(x: BigInt, y: BigInt): UInt = macro SourceInfoTransform.xyArg
+
+ /** @group SourceInfoTransformMacro */
+ final def do_apply(x: BigInt, y: BigInt)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): UInt =
+ apply(castToInt(x, "High index"), castToInt(y, "Low index"))
+
+ private[chisel3] def unop[T <: Data](sourceInfo: SourceInfo, dest: T, op: PrimOp): T = {
+ requireIsHardware(this, "bits operated on")
+ pushOp(DefPrim(sourceInfo, dest, op, this.ref))
+ }
+ private[chisel3] def binop[T <: Data](sourceInfo: SourceInfo, dest: T, op: PrimOp, other: BigInt): T = {
+ requireIsHardware(this, "bits operated on")
+ pushOp(DefPrim(sourceInfo, dest, op, this.ref, ILit(other)))
+ }
+ private[chisel3] def binop[T <: Data](sourceInfo: SourceInfo, dest: T, op: PrimOp, other: Bits): T = {
+ requireIsHardware(this, "bits operated on")
+ requireIsHardware(other, "bits operated on")
+ pushOp(DefPrim(sourceInfo, dest, op, this.ref, other.ref))
+ }
+ private[chisel3] def compop(sourceInfo: SourceInfo, op: PrimOp, other: Bits): Bool = {
+ requireIsHardware(this, "bits operated on")
+ requireIsHardware(other, "bits operated on")
+ pushOp(DefPrim(sourceInfo, Bool(), op, this.ref, other.ref))
+ }
+ private[chisel3] def redop(sourceInfo: SourceInfo, op: PrimOp): Bool = {
+ requireIsHardware(this, "bits operated on")
+ pushOp(DefPrim(sourceInfo, Bool(), op, this.ref))
+ }
+
+ /** Pad operator
+ *
+ * @param that the width to pad to
+ * @return this @coll zero padded up to width `that`. If `that` is less than the width of the original component,
+ * this method returns the original component.
+ * @note For [[SInt]]s only, this will do sign extension.
+ * @group Bitwise
+ */
+ final def pad(that: Int): this.type = macro SourceInfoTransform.thatArg
+
+ /** @group SourceInfoTransformMacro */
+ def do_pad(that: Int)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): this.type = this.width match {
+ case KnownWidth(w) if w >= that => this
+ case _ => binop(sourceInfo, cloneTypeWidth(this.width max Width(that)), PadOp, that)
+ }
+
+ /** Bitwise inversion operator
+ *
+ * @return this $coll with each bit inverted
+ * @group Bitwise
+ */
+ final def unary_~ (): Bits = macro SourceInfoWhiteboxTransform.noArg
+
+ /** @group SourceInfoTransformMacro */
+ def do_unary_~ (implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Bits
+
+ /** Static left shift operator
+ *
+ * @param that an amount to shift by
+ * @return this $coll with `that` many zeros concatenated to its least significant end
+ * $sumWidthInt
+ * @group Bitwise
+ */
+ // REVIEW TODO: redundant
+ // REVIEW TODO: should these return this.type or Bits?
+ final def << (that: BigInt): Bits = macro SourceInfoWhiteboxTransform.thatArg
+
+ /** @group SourceInfoTransformMacro */
+ def do_<< (that: BigInt)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Bits
+
+ /** Static left shift operator
+ *
+ * @param that an amount to shift by
+ * @return this $coll with `that` many zeros concatenated to its least significant end
+ * $sumWidthInt
+ * @group Bitwise
+ */
+ final def << (that: Int): Bits = macro SourceInfoWhiteboxTransform.thatArg
+
+ /** @group SourceInfoTransformMacro */
+ def do_<< (that: Int)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Bits
+
+ /** Dynamic left shift operator
+ *
+ * @param that a hardware component
+ * @return this $coll dynamically shifted left by `that` many places, shifting in zeros from the right
+ * @note The width of the returned $coll is `width of this + pow(2, width of that) - 1`.
+ * @group Bitwise
+ */
+ final def << (that: UInt): Bits = macro SourceInfoWhiteboxTransform.thatArg
+
+ /** @group SourceInfoTransformMacro */
+ def do_<< (that: UInt)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Bits
+
+ /** Static right shift operator
+ *
+ * @param that an amount to shift by
+ * @return this $coll with `that` many least significant bits truncated
+ * $unchangedWidth
+ * @group Bitwise
+ */
+ // REVIEW TODO: redundant
+ final def >> (that: BigInt): Bits = macro SourceInfoWhiteboxTransform.thatArg
+
+ /** @group SourceInfoTransformMacro */
+ def do_>> (that: BigInt)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Bits
+
+ /** Static right shift operator
+ *
+ * @param that an amount to shift by
+ * @return this $coll with `that` many least significant bits truncated
+ * $unchangedWidth
+ * @group Bitwise
+ */
+ final def >> (that: Int): Bits = macro SourceInfoWhiteboxTransform.thatArg
+
+ /** @group SourceInfoTransformMacro */
+ def do_>> (that: Int)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Bits
+
+ /** Dynamic right shift operator
+ *
+ * @param that a hardware component
+ * @return this $coll dynamically shifted right by the value of `that` component, inserting zeros into the most
+ * significant bits.
+ * $unchangedWidth
+ * @group Bitwise
+ */
+ final def >> (that: UInt): Bits = macro SourceInfoWhiteboxTransform.thatArg
+
+ /** @group SourceInfoTransformMacro */
+ def do_>> (that: UInt)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Bits
+
+ /** Returns the contents of this wire as a [[scala.collection.Seq]] of [[Bool]]. */
+ final def toBools(): Seq[Bool] = macro SourceInfoTransform.noArg
+
+ /** @group SourceInfoTransformMacro */
+ @chiselRuntimeDeprecated
+ @deprecated("Use asBools instead", "3.2")
+ def do_toBools(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Seq[Bool] = do_asBools
+
+ /** Returns the contents of this wire as a [[scala.collection.Seq]] of [[Bool]]. */
+ final def asBools(): Seq[Bool] = macro SourceInfoTransform.noArg
+
+ /** @group SourceInfoTransformMacro */
+ def do_asBools(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Seq[Bool] =
+ Seq.tabulate(this.getWidth)(i => this(i))
+
+ /** Reinterpret this $coll as an [[SInt]]
+ *
+ * @note The arithmetic value is not preserved if the most-significant bit is set. For example, a [[UInt]] of
+ * width 3 and value 7 (0b111) would become an [[SInt]] of width 3 and value -1.
+ */
+ final def asSInt(): SInt = macro SourceInfoTransform.noArg
+
+ /** @group SourceInfoTransformMacro */
+ def do_asSInt(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): SInt
+
+ /** Reinterpret this $coll as a [[FixedPoint]].
+ *
+ * @note The value is not guaranteed to be preserved. For example, a [[UInt]] of width 3 and value 7 (0b111) would
+ * become a [[FixedPoint]] with value -1. The interpretation of the number is also affected by the specified binary
+ * point. '''Caution is advised!'''
+ */
+ final def asFixedPoint(that: BinaryPoint): FixedPoint = macro SourceInfoTransform.thatArg
+
+ /** @group SourceInfoTransformMacro */
+ def do_asFixedPoint(that: BinaryPoint)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): FixedPoint = {
+ throwException(s"Cannot call .asFixedPoint on $this")
+ }
+
+ /** Reinterpret cast as a Interval.
+ *
+ * @note value not guaranteed to be preserved: for example, an UInt of width
+ * 3 and value 7 (0b111) would become a FixedInt with value -1, the interpretation
+ * of the number is also affected by the specified binary point. Caution advised
+ */
+ final def asInterval(that: IntervalRange): Interval = macro SourceInfoTransform.thatArg
+
+ def do_asInterval(that: IntervalRange)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Interval = {
+ throwException(s"Cannot call .asInterval on $this")
+ }
+
+ final def do_asBool(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Bool = {
+ width match {
+ case KnownWidth(1) => this(0)
+ case _ => throwException(s"can't covert ${this.getClass.getSimpleName}$width to Bool")
+ }
+ }
+
+ @chiselRuntimeDeprecated
+ @deprecated("Use asBool instead", "3.2")
+ final def do_toBool(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Bool = do_asBool
+
+ /** Concatenation operator
+ *
+ * @param that a hardware component
+ * @return this $coll concatenated to the most significant end of `that`
+ * $sumWidth
+ * @group Bitwise
+ */
+ final def ## (that: Bits): UInt = macro SourceInfoTransform.thatArg
+
+ /** @group SourceInfoTransformMacro */
+ def do_## (that: Bits)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): UInt = {
+ val w = this.width + that.width
+ pushOp(DefPrim(sourceInfo, UInt(w), ConcatOp, this.ref, that.ref))
+ }
+
+ /** Default print as [[Decimal]] */
+ final def toPrintable: Printable = Decimal(this)
+
+ protected final def validateShiftAmount(x: Int): Int = {
+ if (x < 0)
+ Builder.error(s"Negative shift amounts are illegal (got $x)")
+ x
+ }
+}
+
+/** A data type for unsigned integers, represented as a binary bitvector. Defines arithmetic operations between other
+ * integer types.
+ *
+ * @define coll [[UInt]]
+ * @define numType $coll
+ * @define expandingWidth @note The width of the returned $coll is `width of this` + `1`.
+ * @define constantWidth @note The width of the returned $coll is unchanged, i.e., `width of this`.
+ */
+sealed class UInt private[chisel3] (width: Width) extends Bits(width) with Num[UInt] {
+ override def toString: String = {
+ val bindingString = litOption match {
+ case Some(value) => s"($value)"
+ case _ => bindingToString
+ }
+ s"UInt$width$bindingString"
+ }
+
+ private[chisel3] override def typeEquivalent(that: Data): Boolean =
+ that.isInstanceOf[UInt] && this.width == that.width
+
+ private[chisel3] override def cloneTypeWidth(w: Width): this.type =
+ new UInt(w).asInstanceOf[this.type]
+
+ // TODO: refactor to share documentation with Num or add independent scaladoc
+ /** Unary negation (expanding width)
+ *
+ * @return a $coll equal to zero minus this $coll
+ * $constantWidth
+ * @group Arithmetic
+ */
+ final def unary_- (): UInt = macro SourceInfoTransform.noArg
+
+ /** Unary negation (constant width)
+ *
+ * @return a $coll equal to zero minus this $coll shifted right by one.
+ * $constantWidth
+ * @group Arithmetic
+ */
+ final def unary_-% (): UInt = macro SourceInfoTransform.noArg
+
+ /** @group SourceInfoTransformMacro */
+ def do_unary_- (implicit sourceInfo: SourceInfo, compileOptions: CompileOptions) : UInt = 0.U - this
+ /** @group SourceInfoTransformMacro */
+ def do_unary_-% (implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): UInt = 0.U -% this
+
+ override def do_+ (that: UInt)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): UInt = this +% that
+ override def do_- (that: UInt)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): UInt = this -% that
+ override def do_/ (that: UInt)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): UInt =
+ binop(sourceInfo, UInt(this.width), DivideOp, that)
+ override def do_% (that: UInt)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): UInt =
+ binop(sourceInfo, UInt(this.width), RemOp, that)
+ override def do_* (that: UInt)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): UInt =
+ binop(sourceInfo, UInt(this.width + that.width), TimesOp, that)
+
+ /** Multiplication operator
+ *
+ * @param that a hardware [[SInt]]
+ * @return the product of this $coll and `that`
+ * $sumWidth
+ * $singleCycleMul
+ * @group Arithmetic
+ */
+ final def * (that: SInt): SInt = macro SourceInfoTransform.thatArg
+ /** @group SourceInfoTransformMacro */
+ def do_* (that: SInt)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): SInt = that * this
+
+ /** Addition operator (expanding width)
+ *
+ * @param that a hardware $coll
+ * @return the sum of this $coll and `that`
+ * $maxWidthPlusOne
+ * @group Arithmetic
+ */
+ final def +& (that: UInt): UInt = macro SourceInfoTransform.thatArg
+
+ /** Addition operator (constant width)
+ *
+ * @param that a hardware $coll
+ * @return the sum of this $coll and `that`
+ * $maxWidth
+ * @group Arithmetic
+ */
+ final def +% (that: UInt): UInt = macro SourceInfoTransform.thatArg
+
+ /** Subtraction operator (increasing width)
+ *
+ * @param that a hardware $coll
+ * @return the difference of this $coll less `that`
+ * $maxWidthPlusOne
+ * @group Arithmetic
+ */
+ final def -& (that: UInt): UInt = macro SourceInfoTransform.thatArg
+
+ /** Subtraction operator (constant width)
+ *
+ * @param that a hardware $coll
+ * @return the difference of this $coll less `that`
+ * $maxWidth
+ * @group Arithmetic
+ */
+ final def -% (that: UInt): UInt = macro SourceInfoTransform.thatArg
+
+ /** @group SourceInfoTransformMacro */
+ def do_+& (that: UInt)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): UInt =
+ binop(sourceInfo, UInt((this.width max that.width) + 1), AddOp, that)
+ /** @group SourceInfoTransformMacro */
+ def do_+% (that: UInt)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): UInt =
+ (this +& that).tail(1)
+ /** @group SourceInfoTransformMacro */
+ def do_-& (that: UInt)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): UInt =
+ (this subtractAsSInt that).asUInt
+ /** @group SourceInfoTransformMacro */
+ def do_-% (that: UInt)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): UInt =
+ (this subtractAsSInt that).tail(1)
+
+ /** Bitwise and operator
+ *
+ * @param that a hardware $coll
+ * @return the bitwise and of this $coll and `that`
+ * $maxWidth
+ * @group Bitwise
+ */
+ final def & (that: UInt): UInt = macro SourceInfoTransform.thatArg
+
+ /** Bitwise or operator
+ *
+ * @param that a hardware $coll
+ * @return the bitwise or of this $coll and `that`
+ * $maxWidth
+ * @group Bitwise
+ */
+ final def | (that: UInt): UInt = macro SourceInfoTransform.thatArg
+
+ /** Bitwise exclusive or (xor) operator
+ *
+ * @param that a hardware $coll
+ * @return the bitwise xor of this $coll and `that`
+ * $maxWidth
+ * @group Bitwise
+ */
+ final def ^ (that: UInt): UInt = macro SourceInfoTransform.thatArg
+
+ // override def abs: UInt = macro SourceInfoTransform.noArg
+ def do_abs(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): UInt = this
+
+ /** @group SourceInfoTransformMacro */
+ def do_& (that: UInt)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): UInt =
+ binop(sourceInfo, UInt(this.width max that.width), BitAndOp, that)
+ /** @group SourceInfoTransformMacro */
+ def do_| (that: UInt)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): UInt =
+ binop(sourceInfo, UInt(this.width max that.width), BitOrOp, that)
+ /** @group SourceInfoTransformMacro */
+ def do_^ (that: UInt)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): UInt =
+ binop(sourceInfo, UInt(this.width max that.width), BitXorOp, that)
+
+ /** @group SourceInfoTransformMacro */
+ def do_unary_~ (implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): UInt =
+ unop(sourceInfo, UInt(width = width), BitNotOp)
+
+ // REVIEW TODO: Can these be defined on Bits?
+ /** Or reduction operator
+ *
+ * @return a hardware [[Bool]] resulting from every bit of this $coll or'd together
+ * @group Bitwise
+ */
+ final def orR(): Bool = macro SourceInfoTransform.noArg
+
+ /** And reduction operator
+ *
+ * @return a hardware [[Bool]] resulting from every bit of this $coll and'd together
+ * @group Bitwise
+ */
+ final def andR(): Bool = macro SourceInfoTransform.noArg
+
+ /** Exclusive or (xor) reduction operator
+ *
+ * @return a hardware [[Bool]] resulting from every bit of this $coll xor'd together
+ * @group Bitwise
+ */
+ final def xorR(): Bool = macro SourceInfoTransform.noArg
+
+ /** @group SourceInfoTransformMacro */
+ def do_orR(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Bool = redop(sourceInfo, OrReduceOp)
+ /** @group SourceInfoTransformMacro */
+ def do_andR(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Bool = redop(sourceInfo, AndReduceOp)
+ /** @group SourceInfoTransformMacro */
+ def do_xorR(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Bool = redop(sourceInfo, XorReduceOp)
+
+ override def do_< (that: UInt)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Bool = compop(sourceInfo, LessOp, that)
+ override def do_> (that: UInt)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Bool = compop(sourceInfo, GreaterOp, that)
+ override def do_<= (that: UInt)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Bool = compop(sourceInfo, LessEqOp, that)
+ override def do_>= (that: UInt)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Bool = compop(sourceInfo, GreaterEqOp, that)
+
+ @chiselRuntimeDeprecated
+ @deprecated("Use '=/=', which avoids potential precedence problems", "3.0")
+ final def != (that: UInt)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Bool = this =/= that
+
+ /** Dynamic not equals operator
+ *
+ * @param that a hardware $coll
+ * @return a hardware [[Bool]] asserted if this $coll is not equal to `that`
+ * @group Comparison
+ */
+ final def =/= (that: UInt): Bool = macro SourceInfoTransform.thatArg
+
+ /** Dynamic equals operator
+ *
+ * @param that a hardware $coll
+ * @return a hardware [[Bool]] asserted if this $coll is equal to `that`
+ * @group Comparison
+ */
+ final def === (that: UInt): Bool = macro SourceInfoTransform.thatArg
+
+ /** @group SourceInfoTransformMacro */
+ def do_=/= (that: UInt)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Bool = compop(sourceInfo, NotEqualOp, that)
+ /** @group SourceInfoTransformMacro */
+ def do_=== (that: UInt)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Bool = compop(sourceInfo, EqualOp, that)
+
+ /** Unary not
+ *
+ * @return a hardware [[Bool]] asserted if this $coll equals zero
+ * @group Bitwise
+ */
+ final def unary_! () : Bool = macro SourceInfoTransform.noArg
+
+ /** @group SourceInfoTransformMacro */
+ def do_unary_! (implicit sourceInfo: SourceInfo, compileOptions: CompileOptions) : Bool = this === 0.U(1.W)
+
+ override def do_<< (that: Int)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): UInt =
+ binop(sourceInfo, UInt(this.width + that), ShiftLeftOp, validateShiftAmount(that))
+ override def do_<< (that: BigInt)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): UInt =
+ this << castToInt(that, "Shift amount")
+ override def do_<< (that: UInt)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): UInt =
+ binop(sourceInfo, UInt(this.width.dynamicShiftLeft(that.width)), DynamicShiftLeftOp, that)
+ override def do_>> (that: Int)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): UInt =
+ binop(sourceInfo, UInt(this.width.shiftRight(that)), ShiftRightOp, validateShiftAmount(that))
+ override def do_>> (that: BigInt)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): UInt =
+ this >> castToInt(that, "Shift amount")
+ override def do_>> (that: UInt)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): UInt =
+ binop(sourceInfo, UInt(this.width), DynamicShiftRightOp, that)
+
+ /** Conditionally set or clear a bit
+ *
+ * @param off a dynamic offset
+ * @param dat set if true, clear if false
+ * @return a hrdware $coll with bit `off` set or cleared based on the value of `dat`
+ * $unchangedWidth
+ */
+ final def bitSet(off: UInt, dat: Bool): UInt = macro UIntTransform.bitset
+
+ /** @group SourceInfoTransformMacro */
+ def do_bitSet(off: UInt, dat: Bool)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): UInt = {
+ val bit = 1.U(1.W) << off
+ Mux(dat, this | bit, ~(~this | bit))
+ }
+
+ // TODO: this eventually will be renamed as toSInt, once the existing toSInt
+ // completes its deprecation phase.
+ /** Zero extend as [[SInt]]
+ *
+ * @return an [[SInt]] equal to this $coll with an additional zero in its most significant bit
+ * @note The width of the returned [[SInt]] is `width of this` + `1`.
+ */
+ final def zext(): SInt = macro SourceInfoTransform.noArg
+ /** @group SourceInfoTransformMacro */
+ def do_zext(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): SInt =
+ pushOp(DefPrim(sourceInfo, SInt(width + 1), ConvertOp, ref))
+
+ override def do_asSInt(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): SInt =
+ pushOp(DefPrim(sourceInfo, SInt(width), AsSIntOp, ref))
+ override def do_asUInt(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): UInt = this
+ override def do_asFixedPoint(binaryPoint: BinaryPoint)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): FixedPoint = {
+ binaryPoint match {
+ case KnownBinaryPoint(value) =>
+ val iLit = ILit(value)
+ pushOp(DefPrim(sourceInfo, FixedPoint(width, binaryPoint), AsFixedPointOp, ref, iLit))
+ case _ =>
+ throwException(s"cannot call $this.asFixedPoint(binaryPoint=$binaryPoint), you must specify a known binaryPoint")
+ }
+ }
+
+ override def do_asInterval(range: IntervalRange = IntervalRange.Unknown)
+ (implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Interval = {
+ (range.lower, range.upper, range.binaryPoint) match {
+ case (lx: firrtlconstraint.IsKnown, ux: firrtlconstraint.IsKnown, KnownBinaryPoint(bp)) =>
+ // No mechanism to pass open/close to firrtl so need to handle directly
+ val l = lx match {
+ case firrtlir.Open(x) => x + BigDecimal(1) / BigDecimal(BigInt(1) << bp)
+ case firrtlir.Closed(x) => x
+ }
+ val u = ux match {
+ case firrtlir.Open(x) => x - BigDecimal(1) / BigDecimal(BigInt(1) << bp)
+ case firrtlir.Closed(x) => x
+ }
+ val minBI = (l * BigDecimal(BigInt(1) << bp)).setScale(0, BigDecimal.RoundingMode.FLOOR).toBigIntExact.get
+ val maxBI = (u * BigDecimal(BigInt(1) << bp)).setScale(0, BigDecimal.RoundingMode.FLOOR).toBigIntExact.get
+ pushOp(DefPrim(sourceInfo, Interval(range), AsIntervalOp, ref, ILit(minBI), ILit(maxBI), ILit(bp)))
+ case _ =>
+ throwException(
+ s"cannot call $this.asInterval($range), you must specify a known binaryPoint and range")
+ }
+ }
+ private[chisel3] override def connectFromBits(that: Bits)(implicit sourceInfo: SourceInfo,
+ compileOptions: CompileOptions): Unit = {
+ this := that.asUInt
+ }
+
+ private def subtractAsSInt(that: UInt)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): SInt =
+ binop(sourceInfo, SInt((this.width max that.width) + 1), SubOp, that)
+}
+
+/** A data type for signed integers, represented as a binary bitvector. Defines arithmetic operations between other
+ * integer types.
+ *
+ * @define coll [[SInt]]
+ * @define numType $coll
+ * @define expandingWidth @note The width of the returned $coll is `width of this` + `1`.
+ * @define constantWidth @note The width of the returned $coll is unchanged, i.e., `width of this`.
+ */
+sealed class SInt private[chisel3] (width: Width) extends Bits(width) with Num[SInt] {
+ override def toString: String = {
+ val bindingString = litOption match {
+ case Some(value) => s"($value)"
+ case _ => bindingToString
+ }
+ s"SInt$width$bindingString"
+ }
+
+ private[chisel3] override def typeEquivalent(that: Data): Boolean =
+ this.getClass == that.getClass && this.width == that.width // TODO: should this be true for unspecified widths?
+
+ private[chisel3] override def cloneTypeWidth(w: Width): this.type =
+ new SInt(w).asInstanceOf[this.type]
+
+ /** Unary negation (expanding width)
+ *
+ * @return a hardware $coll equal to zero minus this $coll
+ * $constantWidth
+ * @group Arithmetic
+ */
+ final def unary_- (): SInt = macro SourceInfoTransform.noArg
+
+ /** Unary negation (constant width)
+ *
+ * @return a hardware $coll equal to zero minus `this` shifted right by one
+ * $constantWidth
+ * @group Arithmetic
+ */
+ final def unary_-% (): SInt = macro SourceInfoTransform.noArg
+
+ /** @group SourceInfoTransformMacro */
+ def unary_- (implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): SInt = 0.S - this
+ /** @group SourceInfoTransformMacro */
+ def unary_-% (implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): SInt = 0.S -% this
+
+ /** add (default - no growth) operator */
+ override def do_+ (that: SInt)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): SInt =
+ this +% that
+ /** subtract (default - no growth) operator */
+ override def do_- (that: SInt)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): SInt =
+ this -% that
+ override def do_* (that: SInt)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): SInt =
+ binop(sourceInfo, SInt(this.width + that.width), TimesOp, that)
+ override def do_/ (that: SInt)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): SInt =
+ binop(sourceInfo, SInt(this.width), DivideOp, that)
+ override def do_% (that: SInt)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): SInt =
+ binop(sourceInfo, SInt(this.width), RemOp, that)
+
+ /** Multiplication operator
+ *
+ * @param that a hardware $coll
+ * @return the product of this $coll and `that`
+ * $sumWidth
+ * $singleCycleMul
+ * @group Arithmetic
+ */
+ final def * (that: UInt): SInt = macro SourceInfoTransform.thatArg
+ /** @group SourceInfoTransformMacro */
+ def do_* (that: UInt)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): SInt = {
+ val thatToSInt = that.zext()
+ val result = binop(sourceInfo, SInt(this.width + thatToSInt.width), TimesOp, thatToSInt)
+ result.tail(1).asSInt
+ }
+
+ /** Addition operator (expanding width)
+ *
+ * @param that a hardware $coll
+ * @return the sum of this $coll and `that`
+ * $maxWidthPlusOne
+ * @group Arithmetic
+ */
+ final def +& (that: SInt): SInt = macro SourceInfoTransform.thatArg
+
+ /** Addition operator (constant width)
+ *
+ * @param that a hardware $coll
+ * @return the sum of this $coll and `that` shifted right by one
+ * $maxWidth
+ * @group Arithmetic
+ */
+ final def +% (that: SInt): SInt = macro SourceInfoTransform.thatArg
+
+ /** Subtraction operator (increasing width)
+ *
+ * @param that a hardware $coll
+ * @return the difference of this $coll less `that`
+ * $maxWidthPlusOne
+ * @group Arithmetic
+ */
+ final def -& (that: SInt): SInt = macro SourceInfoTransform.thatArg
+
+ /** Subtraction operator (constant width)
+ *
+ * @param that a hardware $coll
+ * @return the difference of this $coll less `that` shifted right by one
+ * $maxWidth
+ * @group Arithmetic
+ */
+ final def -% (that: SInt): SInt = macro SourceInfoTransform.thatArg
+
+ /** @group SourceInfoTransformMacro */
+ def do_+& (that: SInt)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): SInt =
+ binop(sourceInfo, SInt((this.width max that.width) + 1), AddOp, that)
+ /** @group SourceInfoTransformMacro */
+ def do_+% (that: SInt)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): SInt =
+ (this +& that).tail(1).asSInt
+ /** @group SourceInfoTransformMacro */
+ def do_-& (that: SInt)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): SInt =
+ binop(sourceInfo, SInt((this.width max that.width) + 1), SubOp, that)
+ /** @group SourceInfoTransformMacro */
+ def do_-% (that: SInt)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): SInt =
+ (this -& that).tail(1).asSInt
+
+ /** Bitwise and operator
+ *
+ * @param that a hardware $coll
+ * @return the bitwise and of this $coll and `that`
+ * $maxWidth
+ * @group Bitwise
+ */
+ final def & (that: SInt): SInt = macro SourceInfoTransform.thatArg
+
+ /** Bitwise or operator
+ *
+ * @param that a hardware $coll
+ * @return the bitwise or of this $coll and `that`
+ * $maxWidth
+ * @group Bitwise
+ */
+ final def | (that: SInt): SInt = macro SourceInfoTransform.thatArg
+
+ /** Bitwise exclusive or (xor) operator
+ *
+ * @param that a hardware $coll
+ * @return the bitwise xor of this $coll and `that`
+ * $maxWidth
+ * @group Bitwise
+ */
+ final def ^ (that: SInt): SInt = macro SourceInfoTransform.thatArg
+
+ /** @group SourceInfoTransformMacro */
+ def do_& (that: SInt)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): SInt =
+ binop(sourceInfo, UInt(this.width max that.width), BitAndOp, that).asSInt
+ /** @group SourceInfoTransformMacro */
+ def do_| (that: SInt)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): SInt =
+ binop(sourceInfo, UInt(this.width max that.width), BitOrOp, that).asSInt
+ /** @group SourceInfoTransformMacro */
+ def do_^ (that: SInt)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): SInt =
+ binop(sourceInfo, UInt(this.width max that.width), BitXorOp, that).asSInt
+
+ /** @group SourceInfoTransformMacro */
+ def do_unary_~ (implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): SInt =
+ unop(sourceInfo, UInt(width = width), BitNotOp).asSInt
+
+ override def do_< (that: SInt)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Bool = compop(sourceInfo, LessOp, that)
+ override def do_> (that: SInt)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Bool = compop(sourceInfo, GreaterOp, that)
+ override def do_<= (that: SInt)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Bool = compop(sourceInfo, LessEqOp, that)
+ override def do_>= (that: SInt)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Bool = compop(sourceInfo, GreaterEqOp, that)
+
+ @chiselRuntimeDeprecated
+ @deprecated("Use '=/=', which avoids potential precedence problems", "3.0")
+ final def != (that: SInt)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Bool = this =/= that
+
+ /** Dynamic not equals operator
+ *
+ * @param that a hardware $coll
+ * @return a hardware [[Bool]] asserted if this $coll is not equal to `that`
+ * @group Comparison
+ */
+ final def =/= (that: SInt): Bool = macro SourceInfoTransform.thatArg
+
+ /** Dynamic equals operator
+ *
+ * @param that a hardware $coll
+ * @return a hardware [[Bool]] asserted if this $coll is equal to `that`
+ * @group Comparison
+ */
+ final def === (that: SInt): Bool = macro SourceInfoTransform.thatArg
+
+ /** @group SourceInfoTransformMacro */
+ def do_=/= (that: SInt)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Bool = compop(sourceInfo, NotEqualOp, that)
+ /** @group SourceInfoTransformMacro */
+ def do_=== (that: SInt)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Bool = compop(sourceInfo, EqualOp, that)
+
+// final def abs(): UInt = macro SourceInfoTransform.noArg
+
+ def do_abs(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): SInt = {
+ Mux(this < 0.S, (-this), this)
+ }
+
+ override def do_<< (that: Int)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): SInt =
+ binop(sourceInfo, SInt(this.width + that), ShiftLeftOp, validateShiftAmount(that))
+ override def do_<< (that: BigInt)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): SInt =
+ this << castToInt(that, "Shift amount")
+ override def do_<< (that: UInt)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): SInt =
+ binop(sourceInfo, SInt(this.width.dynamicShiftLeft(that.width)), DynamicShiftLeftOp, that)
+ override def do_>> (that: Int)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): SInt =
+ binop(sourceInfo, SInt(this.width.shiftRight(that)), ShiftRightOp, validateShiftAmount(that))
+ override def do_>> (that: BigInt)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): SInt =
+ this >> castToInt(that, "Shift amount")
+ override def do_>> (that: UInt)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): SInt =
+ binop(sourceInfo, SInt(this.width), DynamicShiftRightOp, that)
+
+ override def do_asUInt(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): UInt = pushOp(DefPrim(sourceInfo, UInt(this.width), AsUIntOp, ref))
+ override def do_asSInt(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): SInt = this
+ override def do_asFixedPoint(binaryPoint: BinaryPoint)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): FixedPoint = {
+ binaryPoint match {
+ case KnownBinaryPoint(value) =>
+ val iLit = ILit(value)
+ pushOp(DefPrim(sourceInfo, FixedPoint(width, binaryPoint), AsFixedPointOp, ref, iLit))
+ case _ =>
+ throwException(s"cannot call $this.asFixedPoint(binaryPoint=$binaryPoint), you must specify a known binaryPoint")
+ }
+ }
+
+ override def do_asInterval(range: IntervalRange = IntervalRange.Unknown)
+ (implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Interval = {
+ (range.lower, range.upper, range.binaryPoint) match {
+ case (lx: firrtlconstraint.IsKnown, ux: firrtlconstraint.IsKnown, KnownBinaryPoint(bp)) =>
+ // No mechanism to pass open/close to firrtl so need to handle directly
+ val l = lx match {
+ case firrtlir.Open(x) => x + BigDecimal(1) / BigDecimal(BigInt(1) << bp)
+ case firrtlir.Closed(x) => x
+ }
+ val u = ux match {
+ case firrtlir.Open(x) => x - BigDecimal(1) / BigDecimal(BigInt(1) << bp)
+ case firrtlir.Closed(x) => x
+ }
+ //TODO: (chick) Need to determine, what asInterval needs, and why it might need min and max as args -- CAN IT BE UNKNOWN?
+ // Angie's operation: Decimal -> Int -> Decimal loses information. Need to be conservative here?
+ val minBI = (l * BigDecimal(BigInt(1) << bp)).setScale(0, BigDecimal.RoundingMode.FLOOR).toBigIntExact.get
+ val maxBI = (u * BigDecimal(BigInt(1) << bp)).setScale(0, BigDecimal.RoundingMode.FLOOR).toBigIntExact.get
+ pushOp(DefPrim(sourceInfo, Interval(range), AsIntervalOp, ref, ILit(minBI), ILit(maxBI), ILit(bp)))
+ case _ =>
+ throwException(
+ s"cannot call $this.asInterval($range), you must specify a known binaryPoint and range")
+ }
+ }
+
+ private[chisel3] override def connectFromBits(that: Bits)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions) {
+ this := that.asSInt
+ }
+}
+
+sealed trait Reset extends Element with ToBoolable {
+ /** Casts this $coll to an [[AsyncReset]] */
+ final def asAsyncReset(): AsyncReset = macro SourceInfoWhiteboxTransform.noArg
+
+ /** @group SourceInfoTransformMacro */
+ def do_asAsyncReset(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): AsyncReset
+}
+
+object Reset {
+ def apply(): Reset = new ResetType
+}
+
+/** "Abstract" Reset Type inferred in FIRRTL to either [[AsyncReset]] or [[Bool]]
+ *
+ * @note This shares a common interface with [[AsyncReset]] and [[Bool]] but is not their actual
+ * super type due to Bool inheriting from abstract class UInt
+ */
+final class ResetType(private[chisel3] val width: Width = Width(1)) extends Element with Reset {
+ override def toString: String = s"Reset$bindingToString"
+
+ def cloneType: this.type = Reset().asInstanceOf[this.type]
+
+ private[chisel3] def typeEquivalent(that: Data): Boolean =
+ this.getClass == that.getClass
+
+ override def connect(that: Data)(implicit sourceInfo: SourceInfo, connectCompileOptions: CompileOptions): Unit = that match {
+ case _: Reset | DontCare => super.connect(that)(sourceInfo, connectCompileOptions)
+ case _ => super.badConnect(that)(sourceInfo)
+ }
+
+ override def litOption = None
+
+ /** Not really supported */
+ def toPrintable: Printable = PString("Reset")
+
+ override def do_asUInt(implicit sourceInfo: SourceInfo, connectCompileOptions: CompileOptions): UInt = pushOp(DefPrim(sourceInfo, UInt(this.width), AsUIntOp, ref))
+
+ private[chisel3] override def connectFromBits(that: Bits)(implicit sourceInfo: SourceInfo,
+ compileOptions: CompileOptions): Unit = {
+ this := that
+ }
+
+ /** @group SourceInfoTransformMacro */
+ def do_asAsyncReset(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): AsyncReset =
+ pushOp(DefPrim(sourceInfo, AsyncReset(), AsAsyncResetOp, ref))
+
+ /** @group SourceInfoTransformMacro */
+ def do_asBool(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Bool =
+ pushOp(DefPrim(sourceInfo, Bool(), AsUIntOp, ref))
+
+ /** @group SourceInfoTransformMacro */
+ def do_toBool(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Bool = do_asBool
+}
+
+object AsyncReset {
+ def apply(): AsyncReset = new AsyncReset
+}
+
+/** Data type representing asynchronous reset signals
+ *
+ * These signals are similar to [[Clock]]s in that they must be glitch-free for proper circuit
+ * operation. [[Reg]]s defined with the implicit reset being an [[AsyncReset]] will be
+ * asychronously reset registers.
+ */
+sealed class AsyncReset(private[chisel3] val width: Width = Width(1)) extends Element with Reset {
+ override def toString: String = s"AsyncReset$bindingToString"
+
+ def cloneType: this.type = AsyncReset().asInstanceOf[this.type]
+
+ private[chisel3] def typeEquivalent(that: Data): Boolean =
+ this.getClass == that.getClass
+
+ override def connect(that: Data)(implicit sourceInfo: SourceInfo, connectCompileOptions: CompileOptions): Unit = that match {
+ case _: AsyncReset | DontCare => super.connect(that)(sourceInfo, connectCompileOptions)
+ case _ => super.badConnect(that)(sourceInfo)
+ }
+
+ override def litOption = None
+
+ /** Not really supported */
+ def toPrintable: Printable = PString("AsyncReset")
+
+ override def do_asUInt(implicit sourceInfo: SourceInfo, connectCompileOptions: CompileOptions): UInt = pushOp(DefPrim(sourceInfo, UInt(this.width), AsUIntOp, ref))
+
+ // TODO Is this right?
+ private[chisel3] override def connectFromBits(that: Bits)(implicit sourceInfo: SourceInfo,
+ compileOptions: CompileOptions): Unit = {
+ this := that.asBool.asAsyncReset
+ }
+
+ /** @group SourceInfoTransformMacro */
+ def do_asAsyncReset(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): AsyncReset = this
+
+ /** @group SourceInfoTransformMacro */
+ def do_asBool(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Bool =
+ pushOp(DefPrim(sourceInfo, Bool(), AsUIntOp, ref))
+
+ /** @group SourceInfoTransformMacro */
+ def do_toBool(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Bool = do_asBool
+}
+
+// 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.
+ *
+ * @define coll [[Bool]]
+ * @define numType $coll
+ */
+sealed class Bool() extends UInt(1.W) with Reset {
+ override def toString: String = {
+ val bindingString = litToBooleanOption match {
+ case Some(value) => s"($value)"
+ case _ => bindingToString
+ }
+ s"Bool$bindingString"
+ }
+
+ private[chisel3] override def cloneTypeWidth(w: Width): this.type = {
+ require(!w.known || w.get == 1)
+ new Bool().asInstanceOf[this.type]
+ }
+
+ /** Convert to a [[scala.Option]] of [[scala.Boolean]] */
+ def litToBooleanOption: Option[Boolean] = litOption.map {
+ case intVal if intVal == 1 => true
+ case intVal if intVal == 0 => false
+ case intVal => throwException(s"Boolean with unexpected literal value $intVal")
+ }
+
+ /** Convert to a [[scala.Boolean]] */
+ def litToBoolean: Boolean = litToBooleanOption.get
+
+ // REVIEW TODO: Why does this need to exist and have different conventions
+ // than Bits?
+
+ /** Bitwise and operator
+ *
+ * @param that a hardware $coll
+ * @return the bitwise and of this $coll and `that`
+ * @group Bitwise
+ */
+ final def & (that: Bool): Bool = macro SourceInfoTransform.thatArg
+
+ /** Bitwise or operator
+ *
+ * @param that a hardware $coll
+ * @return the bitwise or of this $coll and `that`
+ * @group Bitwise
+ */
+ final def | (that: Bool): Bool = macro SourceInfoTransform.thatArg
+
+ /** Bitwise exclusive or (xor) operator
+ *
+ * @param that a hardware $coll
+ * @return the bitwise xor of this $coll and `that`
+ * @group Bitwise
+ */
+ final def ^ (that: Bool): Bool = macro SourceInfoTransform.thatArg
+
+ /** @group SourceInfoTransformMacro */
+ def do_& (that: Bool)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Bool =
+ binop(sourceInfo, Bool(), BitAndOp, that)
+ /** @group SourceInfoTransformMacro */
+ def do_| (that: Bool)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Bool =
+ binop(sourceInfo, Bool(), BitOrOp, that)
+ /** @group SourceInfoTransformMacro */
+ def do_^ (that: Bool)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Bool =
+ binop(sourceInfo, Bool(), BitXorOp, that)
+
+ /** @group SourceInfoTransformMacro */
+ override def do_unary_~ (implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Bool =
+ unop(sourceInfo, Bool(), BitNotOp)
+
+ /** Logical or operator
+ *
+ * @param that a hardware $coll
+ * @return the lgocial or of this $coll and `that`
+ * @note this is equivalent to [[Bool!.|(that:chisel3\.Bool)* Bool.|)]]
+ * @group Logical
+ */
+ def || (that: Bool): Bool = macro SourceInfoTransform.thatArg
+
+ /** @group SourceInfoTransformMacro */
+ def do_|| (that: Bool)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Bool = this | that
+
+ /** Logical and operator
+ *
+ * @param that a hardware $coll
+ * @return the lgocial and of this $coll and `that`
+ * @note this is equivalent to [[Bool!.&(that:chisel3\.Bool)* Bool.&]]
+ * @group Logical
+ */
+ def && (that: Bool): Bool = macro SourceInfoTransform.thatArg
+
+ /** @group SourceInfoTransformMacro */
+ def do_&& (that: Bool)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Bool = this & that
+
+ /** Reinterprets this $coll as a clock */
+ def asClock(): Clock = macro SourceInfoTransform.noArg
+
+ /** @group SourceInfoTransformMacro */
+ def do_asClock(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Clock = pushOp(DefPrim(sourceInfo, Clock(), AsClockOp, ref))
+
+ /** @group SourceInfoTransformMacro */
+ def do_asAsyncReset(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): AsyncReset =
+ pushOp(DefPrim(sourceInfo, AsyncReset(), AsAsyncResetOp, ref))
+}
+
+package experimental {
+
+ import chisel3.internal.firrtl.BinaryPoint
+
+ /** Chisel types that have binary points support retrieving
+ * literal values as `Double` or `BigDecimal`
+ */
+ trait HasBinaryPoint { self: Bits =>
+ def binaryPoint: BinaryPoint
+
+ /** Return the [[Double]] value of this instance if it is a Literal
+ * @note this method may throw an exception if the literal value won't fit in a Double
+ */
+ def litToDoubleOption: Option[Double] = {
+ litOption match {
+ case Some(bigInt: BigInt) =>
+ Some(Num.toDouble(bigInt, binaryPoint))
+ case _ => None
+ }
+ }
+
+ /** Return the double value of this instance assuming it is a literal (convenience method)
+ */
+ def litToDouble: Double = litToDoubleOption.get
+
+ /** Return the [[BigDecimal]] value of this instance if it is a Literal
+ * @note this method may throw an exception if the literal value won't fit in a BigDecimal
+ */
+ def litToBigDecimalOption: Option[BigDecimal] = {
+ litOption match {
+ case Some(bigInt: BigInt) =>
+ Some(Num.toBigDecimal(bigInt, binaryPoint))
+ case _ => None
+ }
+ }
+
+ /** Return the [[BigDecimal]] value of this instance assuming it is a literal (convenience method)
+ * @return
+ */
+ def litToBigDecimal: BigDecimal = litToBigDecimalOption.get
+ }
+ //scalastyle:off number.of.methods
+ /** A sealed class representing a fixed point number that has a bit width and a binary point The width and binary point
+ * may be inferred.
+ *
+ * IMPORTANT: The API provided here is experimental and may change in the future.
+ *
+ * @param width bit width of the fixed point number
+ * @param binaryPoint the position of the binary point with respect to the right most bit of the width currently this
+ * should be positive but it is hoped to soon support negative points and thus use this field as a
+ * simple exponent
+ * @define coll [[FixedPoint]]
+ * @define numType $coll
+ * @define expandingWidth @note The width of the returned $coll is `width of this` + `1`.
+ * @define constantWidth @note The width of the returned $coll is unchanged, i.e., `width of this`.
+ */
+ sealed class FixedPoint private(width: Width, val binaryPoint: BinaryPoint)
+ extends Bits(width) with Num[FixedPoint] with HasBinaryPoint {
+
+ override def toString: String = {
+ val bindingString = litToDoubleOption match {
+ case Some(value) => s"($value)"
+ case _ => bindingToString
+ }
+ s"FixedPoint$width$binaryPoint$bindingString"
+ }
+
+ private[chisel3] override def typeEquivalent(that: Data): Boolean = that match {
+ case that: FixedPoint => this.width == that.width && this.binaryPoint == that.binaryPoint // TODO: should this be true for unspecified widths?
+ case _ => false
+ }
+
+ private[chisel3] override def cloneTypeWidth(w: Width): this.type =
+ new FixedPoint(w, binaryPoint).asInstanceOf[this.type]
+
+ override def connect(that: Data)(implicit sourceInfo: SourceInfo, connectCompileOptions: CompileOptions): Unit = that match {
+ case _: FixedPoint|DontCare => super.connect(that)
+ case _ => this badConnect that
+ }
+
+ /** Unary negation (expanding width)
+ *
+ * @return a hardware $coll equal to zero minus this $coll
+ * $expandingWidth
+ * @group Arithmetic
+ */
+ final def unary_- (): FixedPoint = macro SourceInfoTransform.noArg
+
+ /** Unary negation (constant width)
+ *
+ * @return a hardware $coll equal to zero minus `this` shifted right by one
+ * $constantWidth
+ * @group Arithmetic
+ */
+ final def unary_-% (): FixedPoint = macro SourceInfoTransform.noArg
+
+ /** @group SourceInfoTransformMacro */
+ def unary_- (implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): FixedPoint = FixedPoint.fromBigInt(0) - this
+ /** @group SourceInfoTransformMacro */
+ def unary_-% (implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): FixedPoint = FixedPoint.fromBigInt(0) -% this
+
+ /** add (default - no growth) operator */
+ override def do_+ (that: FixedPoint)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): FixedPoint =
+ this +% that
+ /** subtract (default - no growth) operator */
+ override def do_- (that: FixedPoint)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): FixedPoint =
+ this -% that
+ override def do_* (that: FixedPoint)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): FixedPoint =
+ binop(sourceInfo, FixedPoint(this.width + that.width, this.binaryPoint + that.binaryPoint), TimesOp, that)
+ override def do_/ (that: FixedPoint)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): FixedPoint =
+ throwException(s"division is illegal on FixedPoint types")
+ override def do_% (that: FixedPoint)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): FixedPoint =
+ throwException(s"mod is illegal on FixedPoint types")
+
+
+ /** Multiplication operator
+ *
+ * @param that a hardware [[UInt]]
+ * @return the product of this $coll and `that`
+ * $sumWidth
+ * $singleCycleMul
+ * @group Arithmetic
+ */
+ final def * (that: UInt): FixedPoint = macro SourceInfoTransform.thatArg
+ /** @group SourceInfoTransformMacro */
+ def do_* (that: UInt)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): FixedPoint =
+ binop(sourceInfo, FixedPoint(this.width + that.width, binaryPoint), TimesOp, that)
+
+ /** Multiplication operator
+ *
+ * @param that a hardware [[SInt]]
+ * @return the product of this $coll and `that`
+ * $sumWidth
+ * $singleCycleMul
+ * @group Arithmetic
+ */
+ final def * (that: SInt): FixedPoint = macro SourceInfoTransform.thatArg
+ /** @group SourceInfoTransformMacro */
+ def do_* (that: SInt)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): FixedPoint =
+ binop(sourceInfo, FixedPoint(this.width + that.width, binaryPoint), TimesOp, that)
+
+ /** Addition operator (expanding width)
+ *
+ * @param that a hardware $coll
+ * @return the sum of this $coll and `that`
+ * $maxWidthPlusOne
+ * @group Arithmetic
+ */
+ final def +& (that: FixedPoint): FixedPoint = macro SourceInfoTransform.thatArg
+
+ /** Addition operator (constant width)
+ *
+ * @param that a hardware $coll
+ * @return the sum of this $coll and `that` shifted right by one
+ * $maxWidth
+ * @group Arithmetic
+ */
+ final def +% (that: FixedPoint): FixedPoint = macro SourceInfoTransform.thatArg
+
+ /** Subtraction operator (increasing width)
+ *
+ * @param that a hardware $coll
+ * @return the difference of this $coll less `that`
+ * $maxWidthPlusOne
+ * @group Arithmetic
+ */
+ final def -& (that: FixedPoint): FixedPoint = macro SourceInfoTransform.thatArg
+
+ /** Subtraction operator (constant width)
+ *
+ * @param that a hardware $coll
+ * @return the difference of this $coll less `that` shifted right by one
+ * $maxWidth
+ * @group Arithmetic
+ */
+ final def -% (that: FixedPoint): FixedPoint = macro SourceInfoTransform.thatArg
+
+ /** @group SourceInfoTransformMacro */
+ def do_+& (that: FixedPoint)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): FixedPoint = {
+ (this.width, that.width, this.binaryPoint, that.binaryPoint) match {
+ case (KnownWidth(thisWidth), KnownWidth(thatWidth), KnownBinaryPoint(thisBP), KnownBinaryPoint(thatBP)) =>
+ val thisIntWidth = thisWidth - thisBP
+ val thatIntWidth = thatWidth - thatBP
+ val newBinaryPoint = thisBP max thatBP
+ val newWidth = (thisIntWidth max thatIntWidth) + newBinaryPoint + 1
+ binop(sourceInfo, FixedPoint(newWidth.W, newBinaryPoint.BP), AddOp, that)
+ case _ =>
+ val newBinaryPoint = this.binaryPoint max that.binaryPoint
+ binop(sourceInfo, FixedPoint(UnknownWidth(), newBinaryPoint), AddOp, that)
+ }
+ }
+
+ /** @group SourceInfoTransformMacro */
+ def do_+% (that: FixedPoint)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): FixedPoint =
+ (this +& that).tail(1).asFixedPoint(this.binaryPoint max that.binaryPoint)
+ /** @group SourceInfoTransformMacro */
+ def do_-& (that: FixedPoint)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): FixedPoint = {
+ (this.width, that.width, this.binaryPoint, that.binaryPoint) match {
+ case (KnownWidth(thisWidth), KnownWidth(thatWidth), KnownBinaryPoint(thisBP), KnownBinaryPoint(thatBP)) =>
+ val thisIntWidth = thisWidth - thisBP
+ val thatIntWidth = thatWidth - thatBP
+ val newBinaryPoint = thisBP max thatBP
+ val newWidth = (thisIntWidth max thatIntWidth) + newBinaryPoint + 1
+ binop(sourceInfo, FixedPoint(newWidth.W, newBinaryPoint.BP), SubOp, that)
+ case _ =>
+ val newBinaryPoint = this.binaryPoint max that.binaryPoint
+ binop(sourceInfo, FixedPoint(UnknownWidth(), newBinaryPoint), SubOp, that)
+ }
+ }
+
+ /** @group SourceInfoTransformMacro */
+ def do_-% (that: FixedPoint)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): FixedPoint =
+ (this -& that).tail(1).asFixedPoint(this.binaryPoint max that.binaryPoint)
+
+ /** Bitwise and operator
+ *
+ * @param that a hardware $coll
+ * @return the bitwise and of this $coll and `that`
+ * $maxWidth
+ * @group Bitwise
+ */
+ final def & (that: FixedPoint): FixedPoint = macro SourceInfoTransform.thatArg
+
+ /** Bitwise or operator
+ *
+ * @param that a hardware $coll
+ * @return the bitwise or of this $coll and `that`
+ * $maxWidth
+ * @group Bitwise
+ */
+ final def | (that: FixedPoint): FixedPoint = macro SourceInfoTransform.thatArg
+
+ /** Bitwise exclusive or (xor) operator
+ *
+ * @param that a hardware $coll
+ * @return the bitwise xor of this $coll and `that`
+ * $maxWidth
+ * @group Bitwise
+ */
+ final def ^ (that: FixedPoint): FixedPoint = macro SourceInfoTransform.thatArg
+
+ /** @group SourceInfoTransformMacro */
+ def do_& (that: FixedPoint)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): FixedPoint =
+ throwException(s"And is illegal between $this and $that")
+ /** @group SourceInfoTransformMacro */
+ def do_| (that: FixedPoint)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): FixedPoint =
+ throwException(s"Or is illegal between $this and $that")
+ /** @group SourceInfoTransformMacro */
+ def do_^ (that: FixedPoint)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): FixedPoint =
+ throwException(s"Xor is illegal between $this and $that")
+
+ final def setBinaryPoint(that: Int): FixedPoint = macro SourceInfoTransform.thatArg
+
+ /** @group SourceInfoTransformMacro */
+ def do_setBinaryPoint(that: Int)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): FixedPoint = this.binaryPoint match {
+ case KnownBinaryPoint(value) =>
+ binop(sourceInfo, FixedPoint(this.width + (that - value), KnownBinaryPoint(that)), SetBinaryPoint, that)
+ case _ =>
+ binop(sourceInfo, FixedPoint(UnknownWidth(), KnownBinaryPoint(that)), SetBinaryPoint, that)
+ }
+
+ /** @group SourceInfoTransformMacro */
+ def do_unary_~ (implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): FixedPoint =
+ throwException(s"Not is illegal on $this")
+
+ override def do_< (that: FixedPoint)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Bool = compop(sourceInfo, LessOp, that)
+ override def do_> (that: FixedPoint)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Bool = compop(sourceInfo, GreaterOp, that)
+ override def do_<= (that: FixedPoint)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Bool = compop(sourceInfo, LessEqOp, that)
+ override def do_>= (that: FixedPoint)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Bool = compop(sourceInfo, GreaterEqOp, that)
+
+ final def != (that: FixedPoint): Bool = macro SourceInfoTransform.thatArg
+
+ /** Dynamic not equals operator
+ *
+ * @param that a hardware $coll
+ * @return a hardware [[Bool]] asserted if this $coll is not equal to `that`
+ * @group Comparison
+ */
+ final def =/= (that: FixedPoint): Bool = macro SourceInfoTransform.thatArg
+
+ /** Dynamic equals operator
+ *
+ * @param that a hardware $coll
+ * @return a hardware [[Bool]] asserted if this $coll is equal to `that`
+ * @group Comparison
+ */
+ final def === (that: FixedPoint): Bool = macro SourceInfoTransform.thatArg
+
+ /** @group SourceInfoTransformMacro */
+ def do_!= (that: FixedPoint)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Bool = compop(sourceInfo, NotEqualOp, that)
+ /** @group SourceInfoTransformMacro */
+ def do_=/= (that: FixedPoint)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Bool = compop(sourceInfo, NotEqualOp, that)
+ /** @group SourceInfoTransformMacro */
+ def do_=== (that: FixedPoint)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Bool = compop(sourceInfo, EqualOp, that)
+
+ def do_abs(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): FixedPoint = {
+ // TODO: remove this once we have CompileOptions threaded through the macro system.
+ import chisel3.ExplicitCompileOptions.NotStrict
+ Mux(this < 0.F(0.BP), 0.F(0.BP) - this, this)
+ }
+
+ override def do_<< (that: Int)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): FixedPoint =
+ binop(sourceInfo, FixedPoint(this.width + that, this.binaryPoint), ShiftLeftOp, validateShiftAmount(that))
+ override def do_<< (that: BigInt)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): FixedPoint =
+ (this << castToInt(that, "Shift amount")).asFixedPoint(this.binaryPoint)
+ override def do_<< (that: UInt)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): FixedPoint =
+ binop(sourceInfo, FixedPoint(this.width.dynamicShiftLeft(that.width), this.binaryPoint), DynamicShiftLeftOp, that)
+ override def do_>> (that: Int)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): FixedPoint =
+ binop(sourceInfo, FixedPoint(this.width.shiftRight(that), this.binaryPoint), ShiftRightOp, validateShiftAmount(that))
+ override def do_>> (that: BigInt)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): FixedPoint =
+ (this >> castToInt(that, "Shift amount")).asFixedPoint(this.binaryPoint)
+ override def do_>> (that: UInt)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): FixedPoint =
+ binop(sourceInfo, FixedPoint(this.width, this.binaryPoint), DynamicShiftRightOp, that)
+
+ override def do_asUInt(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): UInt = pushOp(DefPrim(sourceInfo, UInt(this.width), AsUIntOp, ref))
+ override def do_asSInt(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): SInt = pushOp(DefPrim(sourceInfo, SInt(this.width), AsSIntOp, ref))
+
+ override def do_asFixedPoint(binaryPoint: BinaryPoint)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): FixedPoint = {
+ binaryPoint match {
+ case KnownBinaryPoint(value) =>
+ val iLit = ILit(value)
+ pushOp(DefPrim(sourceInfo, FixedPoint(width, binaryPoint), AsFixedPointOp, ref, iLit))
+ case _ =>
+ throwException(s"cannot call $this.asFixedPoint(binaryPoint=$binaryPoint), you must specify a known binaryPoint")
+ }
+ }
+
+ def do_asInterval(binaryPoint: BinaryPoint)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Interval = {
+ throwException(s"cannot call $this.asInterval(binaryPoint=$binaryPoint), you must specify a range")
+ }
+
+ override def do_asInterval(range: IntervalRange = IntervalRange.Unknown)
+ (implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Interval = {
+ (range.lower, range.upper, range.binaryPoint) match {
+ case (lx: firrtlconstraint.IsKnown, ux: firrtlconstraint.IsKnown, KnownBinaryPoint(bp)) =>
+ // No mechanism to pass open/close to firrtl so need to handle directly
+ val l = lx match {
+ case firrtlir.Open(x) => x + BigDecimal(1) / BigDecimal(BigInt(1) << bp)
+ case firrtlir.Closed(x) => x
+ }
+ val u = ux match {
+ case firrtlir.Open(x) => x - BigDecimal(1) / BigDecimal(BigInt(1) << bp)
+ case firrtlir.Closed(x) => x
+ }
+ val minBI = (l * BigDecimal(BigInt(1) << bp)).setScale(0, BigDecimal.RoundingMode.FLOOR).toBigIntExact.get
+ val maxBI = (u * BigDecimal(BigInt(1) << bp)).setScale(0, BigDecimal.RoundingMode.FLOOR).toBigIntExact.get
+ pushOp(DefPrim(sourceInfo, Interval(range), AsIntervalOp, ref, ILit(minBI), ILit(maxBI), ILit(bp)))
+ case _ =>
+ throwException(
+ s"cannot call $this.asInterval($range), you must specify a known binaryPoint and range")
+ }
+ }
+
+ private[chisel3] override def connectFromBits(that: Bits)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions) {
+ // TODO: redefine as just asFixedPoint on that, where FixedPoint.asFixedPoint just works.
+ this := (that match {
+ case fp: FixedPoint => fp.asSInt.asFixedPoint(this.binaryPoint)
+ case _ => that.asFixedPoint(this.binaryPoint)
+ })
+ }
+ }
+
+ /** Use PrivateObject to force users to specify width and binaryPoint by name
+ */
+ sealed trait PrivateType
+ private case object PrivateObject extends PrivateType
+
+ /**
+ * Factory and convenience methods for the FixedPoint class
+ * IMPORTANT: The API provided here is experimental and may change in the future.
+ */
+ object FixedPoint extends NumObject {
+
+ import FixedPoint.Implicits._
+
+ /** Create an FixedPoint type with inferred width. */
+ def apply(): FixedPoint = apply(Width(), BinaryPoint())
+
+ /** Create an FixedPoint type or port with fixed width. */
+ def apply(width: Width, binaryPoint: BinaryPoint): FixedPoint = new FixedPoint(width, binaryPoint)
+
+ /** Create an FixedPoint literal with inferred width from BigInt.
+ * Use PrivateObject to force users to specify width and binaryPoint by name
+ */
+ def fromBigInt(value: BigInt, width: Width, binaryPoint: BinaryPoint): FixedPoint = {
+ apply(value, width, binaryPoint)
+ }
+ /** Create an FixedPoint literal with inferred width from BigInt.
+ * Use PrivateObject to force users to specify width and binaryPoint by name
+ */
+ def fromBigInt(value: BigInt, binaryPoint: BinaryPoint = 0.BP): FixedPoint = {
+ apply(value, Width(), binaryPoint)
+ }
+ /** Create an FixedPoint literal with inferred width from BigInt.
+ * Use PrivateObject to force users to specify width and binaryPoint by name
+ */
+ def fromBigInt(value: BigInt, width: Int, binaryPoint: Int): FixedPoint =
+ if(width == -1) {
+ apply(value, Width(), BinaryPoint(binaryPoint))
+ }
+ else {
+ apply(value, Width(width), BinaryPoint(binaryPoint))
+ }
+ /** Create an FixedPoint literal with inferred width from Double.
+ * Use PrivateObject to force users to specify width and binaryPoint by name
+ */
+ def fromDouble(value: Double, width: Width, binaryPoint: BinaryPoint): FixedPoint = {
+ fromBigInt(
+ toBigInt(value, binaryPoint.get), width = width, binaryPoint = binaryPoint
+ )
+ }
+ /** Create an FixedPoint literal with inferred width from BigDecimal.
+ * Use PrivateObject to force users to specify width and binaryPoint by name
+ */
+ def fromBigDecimal(value: BigDecimal, width: Width, binaryPoint: BinaryPoint): FixedPoint = {
+ fromBigInt(
+ toBigInt(value, binaryPoint.get), width = width, binaryPoint = binaryPoint
+ )
+ }
+
+ /** Create an FixedPoint port with specified width and binary position. */
+ def apply(value: BigInt, width: Width, binaryPoint: BinaryPoint): FixedPoint = {
+ val lit = FPLit(value, width, binaryPoint)
+ val newLiteral = new FixedPoint(lit.width, lit.binaryPoint)
+ // Ensure we have something capable of generating a name.
+ lit.bindLitArg(newLiteral)
+ }
+
+
+
+ object Implicits {
+
+ implicit class fromDoubleToLiteral(double: Double) {
+ def F(binaryPoint: BinaryPoint): FixedPoint = {
+ FixedPoint.fromDouble(double, Width(), binaryPoint)
+ }
+
+ def F(width: Width, binaryPoint: BinaryPoint): FixedPoint = {
+ FixedPoint.fromDouble(double, width, binaryPoint)
+ }
+ }
+
+ implicit class fromBigDecimalToLiteral(bigDecimal: BigDecimal) {
+ def F(binaryPoint: BinaryPoint): FixedPoint = {
+ FixedPoint.fromBigDecimal(bigDecimal, Width(), binaryPoint)
+ }
+
+ def F(width: Width, binaryPoint: BinaryPoint): FixedPoint = {
+ FixedPoint.fromBigDecimal(bigDecimal, width, binaryPoint)
+ }
+ }
+ }
+ }
+
+ //scalastyle:off number.of.methods cyclomatic.complexity
+ /**
+ * A sealed class representing a fixed point number that has a range, an additional
+ * parameter that can determine a minimum and maximum supported value.
+ * The range can be used to reduce the required widths particularly in primitive
+ * operations with other Intervals, the canonical example being
+ * {{{
+ * val one = 1.I
+ * val six = Seq.fill(6)(one).reduce(_ + _)
+ * }}}
+ * A UInt computed in this way would require a [[Width]]
+ * binary point
+ * The width and binary point may be inferred.
+ *
+ * IMPORTANT: The API provided here is experimental and may change in the future.
+ *
+ * @param range a range specifies min, max and binary point
+ */
+ sealed class Interval private[chisel3] (val range: chisel3.internal.firrtl.IntervalRange)
+ extends Bits(range.getWidth) with Num[Interval] with HasBinaryPoint {
+
+ override def toString: String = {
+ val bindingString = litOption match {
+ case Some(value) => s"($value)"
+ case _ => bindingToString
+ }
+ s"Interval$width$bindingString"
+ }
+
+ private[chisel3] override def cloneTypeWidth(w: Width): this.type =
+ new Interval(range).asInstanceOf[this.type]
+
+ //scalastyle:off cyclomatic.complexity
+ def toType: String = {
+ val zdec1 = """([+\-]?[0-9]\d*)(\.[0-9]*[1-9])(0*)""".r
+ val zdec2 = """([+\-]?[0-9]\d*)(\.0*)""".r
+ val dec = """([+\-]?[0-9]\d*)(\.[0-9]\d*)""".r
+ val int = """([+\-]?[0-9]\d*)""".r
+ def dec2string(v: BigDecimal): String = v.toString match {
+ case zdec1(x, y, z) => x + y
+ case zdec2(x, y) => x
+ case other => other
+ }
+
+ val lowerString = range.lower match {
+ case firrtlir.Open(l) => s"(${dec2string(l)}, "
+ case firrtlir.Closed(l) => s"[${dec2string(l)}, "
+ case firrtlir.UnknownBound => s"[?, "
+ case _ => s"[?, "
+ }
+ val upperString = range.upper match {
+ case firrtlir.Open(u) => s"${dec2string(u)})"
+ case firrtlir.Closed(u) => s"${dec2string(u)}]"
+ case firrtlir.UnknownBound => s"?]"
+ case _ => s"?]"
+ }
+ val bounds = lowerString + upperString
+
+ val pointString = range.binaryPoint match {
+ case KnownBinaryPoint(i) => "." + i.toString
+ case _ => ""
+ }
+ "Interval" + bounds + pointString
+ }
+
+ private[chisel3] override def typeEquivalent(that: Data): Boolean =
+ that.isInstanceOf[Interval] && this.width == that.width
+
+ def binaryPoint: BinaryPoint = range.binaryPoint
+
+ override def connect(that: Data)(implicit sourceInfo: SourceInfo, connectCompileOptions: CompileOptions): Unit = {
+ that match {
+ case _: Interval|DontCare => super.connect(that)
+ case _ => this badConnect that
+ }
+ }
+
+ final def unary_-(): Interval = macro SourceInfoTransform.noArg
+ final def unary_-%(): Interval = macro SourceInfoTransform.noArg
+
+ def unary_-(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Interval = {
+ Interval.Zero - this
+ }
+ def unary_-%(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Interval = {
+ Interval.Zero -% this
+ }
+
+ /** add (default - growing) operator */
+ override def do_+(that: Interval)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Interval =
+ this +& that
+ /** subtract (default - growing) operator */
+ override def do_-(that: Interval)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Interval =
+ this -& that
+ override def do_*(that: Interval)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Interval =
+ binop(sourceInfo, Interval(this.range * that.range), TimesOp, that)
+
+ override def do_/(that: Interval)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Interval =
+ throwException(s"division is illegal on Interval types")
+ override def do_%(that: Interval)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Interval =
+ throwException(s"mod is illegal on Interval types")
+
+ /** add (width +1) operator */
+ final def +&(that: Interval): Interval = macro SourceInfoTransform.thatArg
+ /** add (no growth) operator */
+ final def +%(that: Interval): Interval = macro SourceInfoTransform.thatArg
+ /** subtract (width +1) operator */
+ final def -&(that: Interval): Interval = macro SourceInfoTransform.thatArg
+ /** subtract (no growth) operator */
+ final def -%(that: Interval): Interval = macro SourceInfoTransform.thatArg
+
+ def do_+&(that: Interval)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Interval = {
+ binop(sourceInfo, Interval(this.range +& that.range), AddOp, that)
+ }
+
+ def do_+%(that: Interval)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Interval = {
+ throwException(s"Non-growing addition is not supported on Intervals: ${sourceInfo}")
+ }
+
+ def do_-&(that: Interval)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Interval = {
+ binop(sourceInfo, Interval(this.range -& that.range), SubOp, that)
+ }
+
+ def do_-%(that: Interval)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Interval = {
+ throwException(s"Non-growing subtraction is not supported on Intervals: ${sourceInfo}, try squeeze")
+ }
+
+ final def &(that: Interval): Interval = macro SourceInfoTransform.thatArg
+ final def |(that: Interval): Interval = macro SourceInfoTransform.thatArg
+ final def ^(that: Interval): Interval = macro SourceInfoTransform.thatArg
+
+ def do_&(that: Interval)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Interval =
+ throwException(s"And is illegal between $this and $that")
+ def do_|(that: Interval)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Interval =
+ throwException(s"Or is illegal between $this and $that")
+ def do_^(that: Interval)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Interval =
+ throwException(s"Xor is illegal between $this and $that")
+
+ final def setPrecision(that: Int): Interval = macro SourceInfoTransform.thatArg
+
+ // Precision change changes range -- see firrtl PrimOps (requires floor)
+ // aaa.bbb -> aaa.bb for sbp(2)
+ def do_setPrecision(that: Int)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Interval = {
+ val newBinaryPoint = BinaryPoint(that)
+ val newIntervalRange = this.range.setPrecision(newBinaryPoint)
+ binop(sourceInfo, Interval(newIntervalRange), SetBinaryPoint, that)
+ }
+
+ /** Increase the precision of this Interval, moves the binary point to the left.
+ * aaa.bbb -> aaa.bbb00
+ * @param that how many bits to shift binary point
+ * @return
+ */
+ final def increasePrecision(that: Int): Interval = macro SourceInfoTransform.thatArg
+
+ def do_increasePrecision(that: Int)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Interval = {
+ assert(that > 0, s"Must increase precision by an integer greater than zero.")
+ val newBinaryPoint = BinaryPoint(that)
+ val newIntervalRange = this.range.incPrecision(newBinaryPoint)
+ binop(sourceInfo, Interval(newIntervalRange), IncreasePrecision, that)
+ }
+
+ /** Decrease the precision of this Interval, moves the binary point to the right.
+ * aaa.bbb -> aaa.b
+ *
+ * @param that number of bits to move binary point
+ * @return
+ */
+ final def decreasePrecision(that: Int): Interval = macro SourceInfoTransform.thatArg
+
+ def do_decreasePrecision(that: Int)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Interval = {
+ assert(that > 0, s"Must decrease precision by an integer greater than zero.")
+ val newBinaryPoint = BinaryPoint(that)
+ val newIntervalRange = this.range.decPrecision(newBinaryPoint)
+ binop(sourceInfo, Interval(newIntervalRange), DecreasePrecision, that)
+ }
+
+ /** Returns this wire bitwise-inverted. */
+ def do_unary_~ (implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Interval =
+ throwException(s"Not is illegal on $this")
+
+ override def do_< (that: Interval)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Bool = compop(sourceInfo, LessOp, that)
+ override def do_> (that: Interval)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Bool = compop(sourceInfo, GreaterOp, that)
+ override def do_<= (that: Interval)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Bool = compop(sourceInfo, LessEqOp, that)
+ override def do_>= (that: Interval)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Bool = compop(sourceInfo, GreaterEqOp, that)
+
+ final def != (that: Interval): Bool = macro SourceInfoTransform.thatArg
+ final def =/= (that: Interval): Bool = macro SourceInfoTransform.thatArg
+ final def === (that: Interval): Bool = macro SourceInfoTransform.thatArg
+
+ def do_!= (that: Interval)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Bool = compop(sourceInfo, NotEqualOp, that)
+ def do_=/= (that: Interval)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Bool = compop(sourceInfo, NotEqualOp, that)
+ def do_=== (that: Interval)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Bool = compop(sourceInfo, EqualOp, that)
+
+ // final def abs(): UInt = macro SourceInfoTransform.noArg
+
+ def do_abs(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Interval = {
+ Mux(this < Interval.Zero, (Interval.Zero - this), this)
+ }
+
+ override def do_<< (that: Int)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Interval =
+ binop(sourceInfo, Interval(this.range << that), ShiftLeftOp, that)
+
+ override def do_<< (that: BigInt)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Interval =
+ do_<<(that.toInt)
+
+ override def do_<< (that: UInt)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Interval = {
+ binop(sourceInfo, Interval(this.range << that), DynamicShiftLeftOp, that)
+ }
+
+ override def do_>> (that: Int)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Interval = {
+ binop(sourceInfo, Interval(this.range >> that), ShiftRightOp, that)
+ }
+
+ override def do_>> (that: BigInt)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Interval =
+ do_>>(that.toInt)
+
+ override def do_>> (that: UInt)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Interval = {
+ binop(sourceInfo, Interval(this.range >> that), DynamicShiftRightOp, that)
+ }
+
+ /**
+ * Squeeze returns the intersection of the ranges this interval and that Interval
+ * Ignores binary point of argument
+ * Treat as an unsafe cast; gives undefined behavior if this signal's value is outside of the resulting range
+ * Adds no additional hardware; this strictly an unsafe type conversion to use at your own risk
+ * @param that
+ * @return
+ */
+ final def squeeze(that: Interval): Interval = macro SourceInfoTransform.thatArg
+ def do_squeeze(that: Interval)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Interval = {
+ val other = that
+ requireIsHardware(this, s"'this' ($this)")
+ requireIsHardware(other, s"'other' ($other)")
+ pushOp(DefPrim(sourceInfo, Interval(this.range.squeeze(that.range)), SqueezeOp, this.ref, other.ref))
+ }
+
+ /**
+ * Squeeze returns the intersection of the ranges this interval and that UInt
+ * Currently, that must have a defined width
+ * Treat as an unsafe cast; gives undefined behavior if this signal's value is outside of the resulting range
+ * Adds no additional hardware; this strictly an unsafe type conversion to use at your own risk
+ * @param that an UInt whose properties determine the squeezing
+ * @return
+ */
+ final def squeeze(that: UInt): Interval = macro SourceInfoTransform.thatArg
+ def do_squeeze(that: UInt)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Interval = {
+ that.widthOption match {
+ case Some(w) =>
+ do_squeeze(Wire(Interval(IntervalRange(that.width, BinaryPoint(0)))))
+ case _ =>
+ throwException(s"$this.squeeze($that) requires an UInt argument with a known width")
+ }
+ }
+
+ /**
+ * Squeeze returns the intersection of the ranges this interval and that SInt
+ * Currently, that must have a defined width
+ * Treat as an unsafe cast; gives undefined behavior if this signal's value is outside of the resulting range
+ * Adds no additional hardware; this strictly an unsafe type conversion to use at your own risk
+ * @param that an SInt whose properties determine the squeezing
+ * @return
+ */
+ final def squeeze(that: SInt): Interval = macro SourceInfoTransform.thatArg
+ def do_squeeze(that: SInt)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Interval = {
+ that.widthOption match {
+ case Some(w) =>
+ do_squeeze(Wire(Interval(IntervalRange(that.width, BinaryPoint(0)))))
+ case _ =>
+ throwException(s"$this.squeeze($that) requires an SInt argument with a known width")
+ }
+ }
+
+ /**
+ * Squeeze returns the intersection of the ranges this interval and that IntervalRange
+ * Ignores binary point of argument
+ * Treat as an unsafe cast; gives undefined behavior if this signal's value is outside of the resulting range
+ * Adds no additional hardware; this strictly an unsafe type conversion to use at your own risk
+ * @param that an Interval whose properties determine the squeezing
+ * @return
+ */
+ final def squeeze(that: IntervalRange): Interval = macro SourceInfoTransform.thatArg
+ def do_squeeze(that: IntervalRange)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Interval = {
+ val intervalLitOpt = Interval.getSmallestLegalLit(that)
+ val intervalLit = intervalLitOpt.getOrElse(
+ throwException(s"$this.squeeze($that) requires an Interval range with known lower and upper bounds")
+ )
+ do_squeeze(intervalLit)
+ }
+
+
+ /**
+ * Wrap the value of this [[Interval]] into the range of a different Interval with a presumably smaller range.
+ * Ignores binary point of argument
+ * Errors if requires wrapping more than once
+ * @param that
+ * @return
+ */
+ final def wrap(that: Interval): Interval = macro SourceInfoTransform.thatArg
+
+ def do_wrap(that: Interval)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Interval = {
+ val other = that
+ requireIsHardware(this, s"'this' ($this)")
+ requireIsHardware(other, s"'other' ($other)")
+ pushOp(DefPrim(sourceInfo, Interval(this.range.wrap(that.range)), WrapOp, this.ref, other.ref))
+ }
+
+ /**
+ * Wrap this interval into the range determined by that UInt
+ * Errors if requires wrapping more than once
+ * @param that an UInt whose properties determine the wrap
+ * @return
+ */
+ final def wrap(that: UInt): Interval = macro SourceInfoTransform.thatArg
+ def do_wrap(that: UInt)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Interval = {
+ that.widthOption match {
+ case Some(w) =>
+ val u = BigDecimal(BigInt(1) << w) - 1
+ do_wrap(0.U.asInterval(IntervalRange(firrtlir.Closed(0), firrtlir.Closed(u), BinaryPoint(0))))
+ case _ =>
+ throwException(s"$this.wrap($that) requires UInt with known width")
+ }
+ }
+
+ /**
+ * Wrap this interval into the range determined by an SInt
+ * Errors if requires wrapping more than once
+ * @param that an SInt whose properties determine the bounds of the wrap
+ * @return
+ */
+ final def wrap(that: SInt): Interval = macro SourceInfoTransform.thatArg
+ def do_wrap(that: SInt)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Interval = {
+ that.widthOption match {
+ case Some(w) =>
+ val l = -BigDecimal(BigInt(1) << (that.getWidth - 1))
+ val u = BigDecimal(BigInt(1) << (that.getWidth - 1)) - 1
+ do_wrap(Wire(Interval(IntervalRange(firrtlir.Closed(l), firrtlir.Closed(u), BinaryPoint(0)))))
+ case _ =>
+ throwException(s"$this.wrap($that) requires SInt with known width")
+ }
+ }
+
+ /**
+ * Wrap this interval into the range determined by an IntervalRange
+ * Adds hardware to change values outside of wrapped range to be at the boundary
+ * Errors if requires wrapping more than once
+ * Ignores binary point of argument
+ * @param that an Interval whose properties determine the bounds of the wrap
+ * @return
+ */
+ final def wrap(that: IntervalRange): Interval = macro SourceInfoTransform.thatArg
+ def do_wrap(that: IntervalRange)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Interval = {
+ (that.lowerBound, that.upperBound) match {
+ case (lower: firrtlconstraint.IsKnown, upperBound: firrtlconstraint.IsKnown) =>
+ do_wrap(0.U.asInterval(IntervalRange(that.lowerBound, that.upperBound, BinaryPoint(0))))
+ case _ =>
+ throwException(s"$this.wrap($that) requires Interval argument with known lower and upper bounds")
+ }
+ }
+
+ /**
+ * Clip this interval into the range determined by argument's range
+ * Adds hardware to change values outside of clipped range to be at the boundary
+ * Ignores binary point of argument
+ * @param that an Interval whose properties determine the clipping
+ * @return
+ */
+ final def clip(that: Interval): Interval = macro SourceInfoTransform.thatArg
+ def do_clip(that: Interval)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Interval = {
+ binop(sourceInfo, Interval(this.range.clip(that.range)), ClipOp, that)
+ }
+
+ /**
+ * Clip this interval into the range determined by argument's range
+ * Adds hardware to change values outside of clipped range to be at the boundary
+ * @param that an UInt whose width determines the clipping
+ * @return
+ */
+ final def clip(that: UInt): Interval = macro SourceInfoTransform.thatArg
+ def do_clip(that: UInt)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Interval = {
+ require(that.widthKnown, "UInt clip width must be known")
+ val u = BigDecimal(BigInt(1) << that.getWidth) - 1
+ do_clip(Wire(Interval(IntervalRange(firrtlir.Closed(0), firrtlir.Closed(u), BinaryPoint(0)))))
+ }
+
+ /**
+ * Clip this interval into the range determined by argument's range
+ * Adds hardware to move values outside of clipped range to the boundary
+ * @param that an SInt whose width determines the clipping
+ * @return
+ */
+ final def clip(that: SInt): Interval = macro SourceInfoTransform.thatArg
+ def do_clip(that: SInt)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Interval = {
+ require(that.widthKnown, "SInt clip width must be known")
+ val l = -BigDecimal(BigInt(1) << (that.getWidth - 1))
+ val u = BigDecimal(BigInt(1) << (that.getWidth - 1)) - 1
+ do_clip(Wire(Interval(IntervalRange(firrtlir.Closed(l), firrtlir.Closed(u), BinaryPoint(0)))))
+ }
+
+ /**
+ * Clip this interval into the range determined by argument's range
+ * Adds hardware to move values outside of clipped range to the boundary
+ * Ignores binary point of argument
+ * @param that an SInt whose width determines the clipping
+ * @return
+ */
+ final def clip(that: IntervalRange): Interval = macro SourceInfoTransform.thatArg
+ def do_clip(that: IntervalRange)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Interval = {
+ (that.lowerBound, that.upperBound) match {
+ case (lower: firrtlconstraint.IsKnown, upperBound: firrtlconstraint.IsKnown) =>
+ do_clip(0.U.asInterval(IntervalRange(that.lowerBound, that.upperBound, BinaryPoint(0))))
+ case _ =>
+ throwException(s"$this.clip($that) requires Interval argument with known lower and upper bounds")
+ }
+ }
+
+ override def do_asUInt(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): UInt = {
+ pushOp(DefPrim(sourceInfo, UInt(this.width), AsUIntOp, ref))
+ }
+ override def do_asSInt(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): SInt = {
+ pushOp(DefPrim(sourceInfo, SInt(this.width), AsSIntOp, ref))
+ }
+
+ override def do_asFixedPoint(binaryPoint: BinaryPoint)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): FixedPoint = {
+ binaryPoint match {
+ case KnownBinaryPoint(value) =>
+ val iLit = ILit(value)
+ pushOp(DefPrim(sourceInfo, FixedPoint(width, binaryPoint), AsFixedPointOp, ref, iLit))
+ case _ =>
+ throwException(
+ s"cannot call $this.asFixedPoint(binaryPoint=$binaryPoint), you must specify a known binaryPoint")
+ }
+ }
+
+ // TODO: intervals chick INVALID -- not enough args
+ def do_asInterval(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Interval = {
+ pushOp(DefPrim(sourceInfo, Interval(this.range), AsIntervalOp, ref))
+ throwException(s"($this).asInterval must specify arguments INVALID")
+ }
+
+ // TODO:(chick) intervals chick looks like this is wrong and only for FP?
+ def do_fromBits(that: Bits)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): this.type = {
+ /*val res = Wire(this, null).asInstanceOf[this.type]
+ res := (that match {
+ case fp: FixedPoint => fp.asSInt.asFixedPoint(this.binaryPoint)
+ case _ => that.asFixedPoint(this.binaryPoint)
+ })
+ res*/
+ throwException("fromBits INVALID for intervals")
+ }
+
+ private[chisel3] override def connectFromBits(that: Bits)
+ (implicit sourceInfo: SourceInfo, compileOptions: CompileOptions) {
+ this := that.asInterval(this.range)
+ }
+ }
+
+ /** Use PrivateObject to force users to specify width and binaryPoint by name
+ */
+
+ /**
+ * Factory and convenience methods for the Interval class
+ * IMPORTANT: The API provided here is experimental and may change in the future.
+ */
+ object Interval extends NumObject {
+ /** Create an Interval type with inferred width and binary point. */
+ def apply(): Interval = Interval(range"[?,?]")
+
+ /** Create an Interval type with specified width. */
+ def apply(binaryPoint: BinaryPoint): Interval = {
+ val binaryPointString = binaryPoint match {
+ case KnownBinaryPoint(value) => s"$value"
+ case _ => s""
+ }
+ Interval(range"[?,?].$binaryPointString")
+ }
+
+ /** Create an Interval type with specified width. */
+ def apply(width: Width): Interval = Interval(width, 0.BP)
+
+ /** Create an Interval type with specified width and binary point */
+ def apply(width: Width, binaryPoint: BinaryPoint): Interval = {
+ Interval(IntervalRange(width, binaryPoint))
+ }
+
+ /** Create an Interval type with specified range.
+ * @param range defines the properties
+ */
+ def apply(range: IntervalRange): Interval = {
+ new Interval(range)
+ }
+
+ /** Creates a Interval connected to a Interval literal with the value zero */
+ def Zero: Interval = Lit(0, 1.W, 0.BP)
+
+ /** Creates an Interval zero that supports the given range
+ * Useful for creating a Interval register that has a desired number of bits
+ * {{{
+ * val myRegister = RegInit(Interval.Zero(r"[0,12]")
+ * }}}
+ * @param range
+ * @return
+ */
+ def Zero(range: IntervalRange): Interval = Lit(0, range)
+
+ /** Make an interval from this BigInt, the BigInt is treated as bits
+ * So lower binaryPoint number of bits will treated as mantissa
+ *
+ * @param value
+ * @param width
+ * @param binaryPoint
+ * @return
+ */
+ def fromBigInt(value: BigInt, width: Width = Width(), binaryPoint: BinaryPoint = 0.BP): Interval = {
+ Interval.Lit(value, Width(), binaryPoint)
+ }
+
+ /** Create an Interval literal with inferred width from Double.
+ * Use PrivateObject to force users to specify width and binaryPoint by name
+ */
+ def fromDouble(value: Double, dummy: PrivateType = PrivateObject,
+ width: Width, binaryPoint: BinaryPoint): Interval = {
+ fromBigInt(
+ toBigInt(value, binaryPoint), width = width, binaryPoint = binaryPoint
+ )
+ }
+
+ /** Create an Interval literal with inferred width from Double.
+ * Use PrivateObject to force users to specify width and binaryPoint by name
+ */
+ def fromBigDecimal(value: Double, dummy: PrivateType = PrivateObject,
+ width: Width, binaryPoint: BinaryPoint): Interval = {
+ fromBigInt(
+ toBigInt(value, binaryPoint), width = width, binaryPoint = binaryPoint
+ )
+ }
+
+ protected[chisel3] def Lit(value: BigInt, width: Width, binaryPoint: BinaryPoint): Interval = {
+ width match {
+ case KnownWidth(w) =>
+ if(value >= 0 && value.bitLength >= w || value < 0 && value.bitLength > w) {
+ throw new ChiselException(
+ s"Error literal interval value $value is too many bits for specified width $w"
+ )
+ }
+ case _ =>
+ }
+ val lit = IntervalLit(value, width, binaryPoint)
+ val bound = firrtlir.Closed(Interval.toBigDecimal(value, binaryPoint.asInstanceOf[KnownBinaryPoint].value))
+ val result = new Interval(IntervalRange(bound, bound, binaryPoint))
+ lit.bindLitArg(result)
+ }
+
+ protected[chisel3] def Lit(value: BigInt, range: IntervalRange): Interval = {
+ val lit = IntervalLit(value, range.getWidth, range.binaryPoint)
+ val bigDecimal = BigDecimal(value) / (1 << lit.binaryPoint.get)
+ val inRange = (range.lowerBound, range.upperBound) match {
+ case (firrtlir.Closed(l), firrtlir.Closed(u)) => l <= bigDecimal && bigDecimal <= u
+ case (firrtlir.Closed(l), firrtlir.Open(u)) => l <= bigDecimal && bigDecimal < u
+ case (firrtlir.Open(l), firrtlir.Closed(u)) => l < bigDecimal && bigDecimal <= u
+ case (firrtlir.Open(l), firrtlir.Open(u)) => l < bigDecimal && bigDecimal < u
+ }
+ if(! inRange) {
+ throw new ChiselException(
+ s"Error literal interval value $bigDecimal is not contained in specified range $range"
+ )
+ }
+ val result = Interval(range)
+ lit.bindLitArg(result)
+ }
+
+ /**
+ * This returns the smallest Interval literal that can legally fit in range, if possible
+ * If the lower bound or binary point is not known then return None
+ *
+ * @param range use to figure low number
+ * @return
+ */
+ def getSmallestLegalLit(range: IntervalRange): Option[Interval] = {
+ val bp = range.binaryPoint
+ range.lowerBound match {
+ case firrtlir.Closed(lowerBound) =>
+ Some(Interval.Lit(toBigInt(lowerBound.toDouble, bp), width = range.getWidth, bp))
+ case firrtlir.Open(lowerBound) =>
+ Some(Interval.Lit(toBigInt(lowerBound.toDouble, bp) + BigInt(1), width = range.getWidth, bp))
+ case _ =>
+ None
+ }
+ }
+
+ /**
+ * This returns the largest Interval literal that can legally fit in range, if possible
+ * If the upper bound or binary point is not known then return None
+ *
+ * @param range use to figure low number
+ * @return
+ */
+ def getLargestLegalLit(range: IntervalRange): Option[Interval] = {
+ val bp = range.binaryPoint
+ range.upperBound match {
+ case firrtlir.Closed(upperBound) =>
+ Some(Interval.Lit(toBigInt(upperBound.toDouble, bp), width = range.getWidth, bp))
+ case firrtlir.Open(upperBound) =>
+ Some(Interval.Lit(toBigInt(upperBound.toDouble, bp) - BigInt(1), width = range.getWidth, bp))
+ case _ =>
+ None
+ }
+ }
+
+ /** Contains the implicit classes used to provide the .I methods to create intervals
+ * from the standard numberic types.
+ * {{{
+ * val x = 7.I
+ * val y = 7.5.I(4.BP)
+ * }}}
+ */
+ object Implicits {
+ implicit class fromBigIntToLiteralInterval(bigInt: BigInt) {
+ def I: Interval = {
+ Interval.Lit(bigInt, width = Width(), 0.BP)
+ }
+
+ def I(binaryPoint: BinaryPoint): Interval = {
+ Interval.Lit(bigInt, width = Width(), binaryPoint = binaryPoint)
+ }
+
+ def I(width: Width, binaryPoint: BinaryPoint): Interval = {
+ Interval.Lit(bigInt, width, binaryPoint)
+ }
+
+ def I(range: IntervalRange): Interval = {
+ Interval.Lit(bigInt, range)
+ }
+ }
+
+ implicit class fromIntToLiteralInterval(int: Int) extends fromBigIntToLiteralInterval(int)
+ implicit class fromLongToLiteralInterval(long: Long) extends fromBigIntToLiteralInterval(long)
+
+ implicit class fromBigDecimalToLiteralInterval(bigDecimal: BigDecimal) {
+ def I: Interval = {
+ Interval.Lit(Interval.toBigInt(bigDecimal, 0.BP), width = Width(), 0.BP)
+ }
+
+ def I(binaryPoint: BinaryPoint): Interval = {
+ Interval.Lit(Interval.toBigInt(bigDecimal, binaryPoint), width = Width(), binaryPoint = binaryPoint)
+ }
+
+ def I(width: Width, binaryPoint: BinaryPoint): Interval = {
+ Interval.Lit(Interval.toBigInt(bigDecimal, binaryPoint), width, binaryPoint)
+ }
+
+ def I(range: IntervalRange): Interval = {
+ Interval.Lit(Interval.toBigInt(bigDecimal, range.binaryPoint), range)
+ }
+ }
+
+ implicit class fromDoubleToLiteralInterval(double: Double)
+ extends fromBigDecimalToLiteralInterval(BigDecimal(double))
+ }
+ }
+}
+
+
diff --git a/core/src/main/scala/chisel3/BlackBox.scala b/core/src/main/scala/chisel3/BlackBox.scala
new file mode 100644
index 00000000..f29962d7
--- /dev/null
+++ b/core/src/main/scala/chisel3/BlackBox.scala
@@ -0,0 +1,181 @@
+// See LICENSE for license details.
+
+package chisel3
+
+import chisel3.experimental.{BaseModule, Param}
+import chisel3.internal.BaseBlackBox
+import chisel3.internal.Builder.pushCommand
+import chisel3.internal.firrtl._
+import chisel3.internal.throwException
+import chisel3.internal.sourceinfo.{SourceInfo, UnlocatableSourceInfo}
+
+package internal {
+
+ private[chisel3] abstract class BaseBlackBox extends BaseModule
+
+}
+
+package experimental {
+
+ /** Parameters for BlackBoxes */
+ sealed abstract class Param
+ case class IntParam(value: BigInt) extends Param
+ case class DoubleParam(value: Double) extends Param
+ case class StringParam(value: String) extends Param
+ /** Unquoted String */
+ case class RawParam(value: String) extends Param
+
+ /** 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.
+ *
+ * A variant of BlackBox, this has a more consistent naming scheme in allowing
+ * multiple top-level IO and does not drop the top prefix.
+ *
+ * @example
+ * Some design require a differential input clock to clock the all design.
+ * With the xilinx FPGA for example, a Verilog template named IBUFDS must be
+ * integrated to use differential input:
+ * {{{
+ * IBUFDS #(.DIFF_TERM("TRUE"),
+ * .IOSTANDARD("DEFAULT")) ibufds (
+ * .IB(ibufds_IB),
+ * .I(ibufds_I),
+ * .O(ibufds_O)
+ * );
+ * }}}
+ *
+ * To instantiate it, a BlackBox can be used like following:
+ * {{{
+ * import chisel3._
+ * import chisel3.experimental._
+ *
+ * // Example with Xilinx differential buffer IBUFDS
+ * class IBUFDS extends ExtModule(Map("DIFF_TERM" -> "TRUE", // Verilog parameters
+ * "IOSTANDARD" -> "DEFAULT"
+ * )) {
+ * val O = IO(Output(Clock()))
+ * val I = IO(Input(Clock()))
+ * val IB = IO(Input(Clock()))
+ * }
+ * }}}
+ * @note The parameters API is experimental and may change
+ */
+ abstract class ExtModule(val params: Map[String, Param] = Map.empty[String, Param]) extends BaseBlackBox {
+ private[chisel3] override def generateComponent(): Component = {
+ require(!_closed, "Can't generate module more than once")
+ _closed = true
+
+ val names = nameIds(classOf[ExtModule])
+
+ // Name ports based on reflection
+ for (port <- getModulePorts) {
+ require(names.contains(port), s"Unable to name port $port in $this")
+ port.setRef(ModuleIO(this, _namespace.name(names(port))))
+ }
+
+ // All suggestions are in, force names to every node.
+ // While BlackBoxes are not supposed to have an implementation, we still need to call
+ // _onModuleClose on all nodes (for example, Aggregates use it for recursive naming).
+ for (id <- getIds) {
+ id._onModuleClose
+ }
+
+ val firrtlPorts = getModulePorts map {port => Port(port, port.specifiedDirection)}
+ val component = DefBlackBox(this, name, firrtlPorts, SpecifiedDirection.Unspecified, params)
+ _component = Some(component)
+ component
+ }
+
+ private[chisel3] def initializeInParent(parentCompileOptions: CompileOptions): Unit = {
+ implicit val sourceInfo = UnlocatableSourceInfo
+
+ for (x <- getModulePorts) {
+ pushCommand(DefInvalid(sourceInfo, x.ref))
+ }
+ }
+ }
+}
+
+/** 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
+ * Some design require a differential input clock to clock the all design.
+ * With the xilinx FPGA for example, a Verilog template named IBUFDS must be
+ * integrated to use differential input:
+ * {{{
+ * IBUFDS #(.DIFF_TERM("TRUE"),
+ * .IOSTANDARD("DEFAULT")) ibufds (
+ * .IB(ibufds_IB),
+ * .I(ibufds_I),
+ * .O(ibufds_O)
+ * );
+ * }}}
+ *
+ * To instantiate it, a BlackBox can be used like following:
+ * {{{
+ * import chisel3._
+ * import chisel3.experimental._
+ *
+ * // Example with Xilinx differential buffer IBUFDS
+ * class IBUFDS extends BlackBox(Map("DIFF_TERM" -> "TRUE", // Verilog parameters
+ * "IOSTANDARD" -> "DEFAULT"
+ * )) {
+ * val io = IO(new Bundle {
+ * val O = Output(Clock()) // IO names will be the same
+ * val I = Input(Clock()) // (without 'io_' in prefix)
+ * val IB = Input(Clock()) //
+ * })
+ * }
+ * }}}
+ * @note The parameters API is experimental and may change
+ */
+abstract class BlackBox(val params: Map[String, Param] = Map.empty[String, Param])(implicit compileOptions: CompileOptions) extends BaseBlackBox { // scalastyle:ignore line.size.limit
+ def io: Record
+
+ // Allow access to bindings from the compatibility package
+ protected def _compatIoPortBound() = portsContains(io) // scalastyle:ignore method.name
+
+ private[chisel3] override def generateComponent(): Component = {
+ _compatAutoWrapPorts() // pre-IO(...) compatibility hack
+
+ // Restrict IO to just io, clock, and reset
+ require(io != null, "BlackBox must have io")
+ require(portsContains(io), "BlackBox must have io wrapped in IO(...)")
+ require(portsSize == 1, "BlackBox must only have io as IO")
+
+ require(!_closed, "Can't generate module more than once")
+ _closed = true
+
+ val namedPorts = io.elements.toSeq.reverse // ListMaps are stored in reverse order
+
+ // 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) <- namedPorts) {
+ 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 <- getIds; if id ne io) {
+ id._onModuleClose
+ }
+
+ val firrtlPorts = namedPorts map {namedPort => Port(namedPort._2, namedPort._2.specifiedDirection)}
+ val component = DefBlackBox(this, name, firrtlPorts, io.specifiedDirection, params)
+ _component = Some(component)
+ component
+ }
+
+ private[chisel3] def initializeInParent(parentCompileOptions: CompileOptions): Unit = {
+ for ((_, port) <- io.elements) {
+ pushCommand(DefInvalid(UnlocatableSourceInfo, port.ref))
+ }
+ }
+}
diff --git a/core/src/main/scala/chisel3/BoolFactory.scala b/core/src/main/scala/chisel3/BoolFactory.scala
new file mode 100644
index 00000000..bccd6414
--- /dev/null
+++ b/core/src/main/scala/chisel3/BoolFactory.scala
@@ -0,0 +1,22 @@
+// See LICENSE for license details.
+
+package chisel3
+
+import chisel3.internal.firrtl.{ULit, Width}
+
+// scalastyle:off method.name
+
+trait BoolFactory {
+ /** Creates an empty Bool.
+ */
+ def apply(): Bool = new Bool()
+
+ /** Creates Bool literal.
+ */
+ protected[chisel3] def Lit(x: Boolean): Bool = {
+ val result = new Bool()
+ val lit = ULit(if (x) 1 else 0, Width(1))
+ // Ensure we have something capable of generating a name.
+ lit.bindLitArg(result)
+ }
+}
diff --git a/core/src/main/scala/chisel3/Clock.scala b/core/src/main/scala/chisel3/Clock.scala
new file mode 100644
index 00000000..d7975b1e
--- /dev/null
+++ b/core/src/main/scala/chisel3/Clock.scala
@@ -0,0 +1,43 @@
+// See LICENSE for license details.
+
+package chisel3
+
+import scala.language.experimental.macros
+import chisel3.internal.Builder.pushOp
+import chisel3.internal.firrtl._
+import chisel3.internal.sourceinfo._
+import chisel3.internal.firrtl.PrimOp.AsUIntOp
+
+object Clock {
+ def apply(): Clock = new Clock
+}
+
+// TODO: Document this.
+sealed class Clock(private[chisel3] val width: Width = Width(1)) extends Element {
+ override def toString: String = s"Clock$bindingToString"
+
+ def cloneType: this.type = Clock().asInstanceOf[this.type]
+
+ private[chisel3] def typeEquivalent(that: Data): Boolean =
+ this.getClass == that.getClass
+
+ override def connect(that: Data)(implicit sourceInfo: SourceInfo, connectCompileOptions: CompileOptions): Unit = that match { // scalastyle:ignore line.size.limit
+ case _: Clock => super.connect(that)(sourceInfo, connectCompileOptions)
+ case _ => super.badConnect(that)(sourceInfo)
+ }
+
+ override def litOption: Option[BigInt] = None
+
+ /** Not really supported */
+ def toPrintable: Printable = PString("CLOCK")
+
+ /** Returns the contents of the clock wire as a [[Bool]]. */
+ final def asBool(): Bool = macro SourceInfoTransform.noArg
+ def do_asBool(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Bool = this.asUInt().asBool()
+
+ override def do_asUInt(implicit sourceInfo: SourceInfo, connectCompileOptions: CompileOptions): UInt = pushOp(DefPrim(sourceInfo, UInt(this.width), AsUIntOp, ref)) // scalastyle:ignore line.size.limit
+ private[chisel3] override def connectFromBits(that: Bits)(implicit sourceInfo: SourceInfo,
+ compileOptions: CompileOptions): Unit = {
+ this := that.asBool.asClock
+ }
+}
diff --git a/core/src/main/scala/chisel3/CompileOptions.scala b/core/src/main/scala/chisel3/CompileOptions.scala
new file mode 100644
index 00000000..ed410c6e
--- /dev/null
+++ b/core/src/main/scala/chisel3/CompileOptions.scala
@@ -0,0 +1,80 @@
+// See LICENSE for license details.
+
+package chisel3
+
+import scala.language.experimental.macros
+import scala.reflect.macros.blackbox.Context
+
+trait CompileOptions {
+ // Should Record connections require a strict match of fields.
+ // If true and the same fields aren't present in both source and sink, a MissingFieldException,
+ // MissingLeftFieldException, or MissingRightFieldException will be thrown.
+ val connectFieldsMustMatch: Boolean
+ // When creating an object that takes a type argument, the argument must be unbound (a pure type).
+ val declaredTypeMustBeUnbound: Boolean
+ // If a connection operator fails, don't try the connection with the operands (source and sink) reversed.
+ val dontTryConnectionsSwapped: Boolean
+ // If connection directionality is not explicit, do not use heuristics to attempt to determine it.
+ val dontAssumeDirectionality: Boolean
+ // Check that referenced Data have actually been declared.
+ val checkSynthesizable: Boolean
+ // Require explicit assignment of DontCare to generate "x is invalid"
+ val explicitInvalidate: Boolean
+ // Should the reset type of Module be a Bool or a Reset
+ val inferModuleReset: Boolean
+}
+
+object CompileOptions {
+ // Provides a low priority Strict default. Can be overridden by importing the NotStrict option.
+ // Implemented as a macro to prevent this from being used inside chisel core.
+ implicit def materialize: CompileOptions = macro materialize_impl
+
+ def materialize_impl(c: Context): c.Tree = {
+ import c.universe._
+ q"_root_.chisel3.ExplicitCompileOptions.Strict"
+ }
+}
+
+object ExplicitCompileOptions {
+ case class CompileOptionsClass (
+ // Should Record connections require a strict match of fields.
+ // If true and the same fields aren't present in both source and sink, a MissingFieldException,
+ // MissingLeftFieldException, or MissingRightFieldException will be thrown.
+ val connectFieldsMustMatch: Boolean,
+ // When creating an object that takes a type argument, the argument must be unbound (a pure type).
+ val declaredTypeMustBeUnbound: Boolean,
+ // If a connection operator fails, don't try the connection with the operands (source and sink) reversed.
+ val dontTryConnectionsSwapped: Boolean,
+ // If connection directionality is not explicit, do not use heuristics to attempt to determine it.
+ val dontAssumeDirectionality: Boolean,
+ // Check that referenced Data have actually been declared.
+ val checkSynthesizable: Boolean,
+ // Require an explicit DontCare assignment to generate a firrtl DefInvalid
+ val explicitInvalidate: Boolean,
+ // Should the reset type of Module be a Bool or a Reset
+ val inferModuleReset: Boolean
+ ) extends CompileOptions
+
+ // Collection of "not strict" connection compile options.
+ // These provide compatibility with existing code.
+ implicit val NotStrict = new CompileOptionsClass (
+ connectFieldsMustMatch = false,
+ declaredTypeMustBeUnbound = false,
+ dontTryConnectionsSwapped = false,
+ dontAssumeDirectionality = false,
+ checkSynthesizable = false,
+ explicitInvalidate = false,
+ inferModuleReset = false
+ )
+
+ // Collection of "strict" connection compile options, preferred for new code.
+ implicit val Strict = new CompileOptionsClass (
+ connectFieldsMustMatch = true,
+ declaredTypeMustBeUnbound = true,
+ dontTryConnectionsSwapped = true,
+ dontAssumeDirectionality = true,
+ checkSynthesizable = true,
+ explicitInvalidate = true,
+ inferModuleReset = true
+ )
+}
diff --git a/core/src/main/scala/chisel3/Data.scala b/core/src/main/scala/chisel3/Data.scala
new file mode 100644
index 00000000..6574a39d
--- /dev/null
+++ b/core/src/main/scala/chisel3/Data.scala
@@ -0,0 +1,729 @@
+// See LICENSE for license details.
+
+package chisel3
+
+import scala.language.experimental.macros
+import chisel3.experimental.{Analog, DataMirror, FixedPoint, Interval}
+import chisel3.internal.Builder.pushCommand
+import chisel3.internal._
+import chisel3.internal.firrtl._
+import chisel3.internal.sourceinfo.{DeprecatedSourceInfo, SourceInfo, SourceInfoTransform, UnlocatableSourceInfo}
+
+/** User-specified directions.
+ */
+sealed abstract class SpecifiedDirection
+object SpecifiedDirection {
+ /** Default user direction, also meaning 'not-flipped'
+ */
+ case object Unspecified extends SpecifiedDirection
+ /** Node and its children are forced as output
+ */
+ case object Output extends SpecifiedDirection
+ /** Node and its children are forced as inputs
+ */
+ case object Input extends SpecifiedDirection
+ /** Mainly for containers, children are flipped.
+ */
+ case object Flip extends SpecifiedDirection
+
+ def flip(dir: SpecifiedDirection): SpecifiedDirection = dir match {
+ case Unspecified => Flip
+ case Flip => Unspecified
+ case Output => Input
+ case Input => Output
+ }
+
+ /** Returns the effective SpecifiedDirection of this node given the parent's effective SpecifiedDirection
+ * and the user-specified SpecifiedDirection of this node.
+ */
+ def fromParent(parentDirection: SpecifiedDirection, thisDirection: SpecifiedDirection): SpecifiedDirection =
+ (parentDirection, thisDirection) match {
+ case (SpecifiedDirection.Output, _) => SpecifiedDirection.Output
+ case (SpecifiedDirection.Input, _) => SpecifiedDirection.Input
+ case (SpecifiedDirection.Unspecified, thisDirection) => thisDirection
+ case (SpecifiedDirection.Flip, thisDirection) => SpecifiedDirection.flip(thisDirection)
+ }
+
+ private[chisel3] def specifiedDirection[T<:Data](source: T)(dir: SpecifiedDirection)(implicit compileOptions: CompileOptions): T = {
+ if (compileOptions.checkSynthesizable) {
+ requireIsChiselType(source)
+ }
+ val out = source.cloneType.asInstanceOf[T]
+ out.specifiedDirection = dir
+ out
+ }
+
+}
+
+/** Resolved directions for both leaf and container nodes, only visible after
+ * a node is bound (since higher-level specifications like Input and Output
+ * can override directions).
+ */
+sealed abstract class ActualDirection
+
+object ActualDirection {
+ /** The object does not exist / is empty and hence has no direction
+ */
+ case object Empty extends ActualDirection
+
+ /** Undirectioned, struct-like
+ */
+ case object Unspecified extends ActualDirection
+ /** Output element, or container with all outputs (even if forced)
+ */
+ case object Output extends ActualDirection
+ /** Input element, or container with all inputs (even if forced)
+ */
+ case object Input extends ActualDirection
+
+ sealed abstract class BidirectionalDirection
+ case object Default extends BidirectionalDirection
+ case object Flipped extends BidirectionalDirection
+
+ case class Bidirectional(dir: BidirectionalDirection) extends ActualDirection
+
+ def fromSpecified(direction: SpecifiedDirection): ActualDirection = direction match {
+ case SpecifiedDirection.Unspecified | SpecifiedDirection.Flip => ActualDirection.Unspecified
+ case SpecifiedDirection.Output => ActualDirection.Output
+ case SpecifiedDirection.Input => ActualDirection.Input
+ }
+
+ /** Determine the actual binding of a container given directions of its children.
+ * Returns None in the case of mixed specified / unspecified directionality.
+ */
+ def fromChildren(childDirections: Set[ActualDirection], containerDirection: SpecifiedDirection):
+ Option[ActualDirection] = {
+ if (childDirections == Set()) { // Sadly, Scala can't do set matching
+ ActualDirection.fromSpecified(containerDirection) match {
+ case ActualDirection.Unspecified => Some(ActualDirection.Empty) // empty direction if relative / no direction
+ case dir => Some(dir) // use assigned direction if specified
+ }
+ } else if (childDirections == Set(ActualDirection.Unspecified)) {
+ Some(ActualDirection.Unspecified)
+ } else if (childDirections == Set(ActualDirection.Input)) {
+ Some(ActualDirection.Input)
+ } else if (childDirections == Set(ActualDirection.Output)) {
+ Some(ActualDirection.Output)
+ } else if (childDirections subsetOf
+ Set(ActualDirection.Output, ActualDirection.Input,
+ ActualDirection.Bidirectional(ActualDirection.Default),
+ ActualDirection.Bidirectional(ActualDirection.Flipped))) {
+ containerDirection match {
+ case SpecifiedDirection.Unspecified => Some(ActualDirection.Bidirectional(ActualDirection.Default))
+ case SpecifiedDirection.Flip => Some(ActualDirection.Bidirectional(ActualDirection.Flipped))
+ case _ => throw new RuntimeException("Unexpected forced Input / Output")
+ }
+ } else {
+ None
+ }
+ }
+}
+
+package experimental {
+
+ /** Experimental hardware construction reflection API
+ */
+ object DataMirror {
+ def widthOf(target: Data): Width = target.width
+ def specifiedDirectionOf(target: Data): SpecifiedDirection = target.specifiedDirection
+ def directionOf(target: Data): ActualDirection = {
+ requireIsHardware(target, "node requested directionality on")
+ target.direction
+ }
+
+ // Returns the top-level module ports
+ // TODO: maybe move to something like Driver or DriverUtils, since this is mainly for interacting
+ // with compiled artifacts (vs. elaboration-time reflection)?
+ def modulePorts(target: BaseModule): Seq[(String, Data)] = target.getChiselPorts
+
+ // Returns all module ports with underscore-qualified names
+ def fullModulePorts(target: BaseModule): Seq[(String, Data)] = {
+ def getPortNames(name: String, data: Data): Seq[(String, Data)] = Seq(name -> data) ++ (data match {
+ case _: Element => Seq()
+ case r: Record => r.elements.toSeq flatMap { case (eltName, elt) => getPortNames(s"${name}_${eltName}", elt) }
+ case v: Vec[_] => v.zipWithIndex flatMap { case (elt, index) => getPortNames(s"${name}_${index}", elt) }
+ })
+ modulePorts(target).flatMap { case (name, data) =>
+ getPortNames(name, data).toList
+ }
+ }
+
+ // Internal reflection-style APIs, subject to change and removal whenever.
+ object internal { // scalastyle:ignore object.name
+ def isSynthesizable(target: Data): Boolean = target.isSynthesizable
+ // For those odd cases where you need to care about object reference and uniqueness
+ def chiselTypeClone[T<:Data](target: Data): T = {
+ target.cloneTypeFull.asInstanceOf[T]
+ }
+ }
+ }
+}
+
+/** Creates a clone of the super-type of the input elements. Super-type is defined as:
+ * - for Bits type of the same class: the cloned type of the largest width
+ * - Bools are treated as UInts
+ * - For other types of the same class are are the same: clone of any of the elements
+ * - Otherwise: fail
+ */
+//scalastyle:off cyclomatic.complexity
+private[chisel3] object cloneSupertype {
+ def apply[T <: Data](elts: Seq[T], createdType: String)(implicit sourceInfo: SourceInfo,
+ compileOptions: CompileOptions): T = {
+ require(!elts.isEmpty, s"can't create $createdType with no inputs")
+
+ val filteredElts = elts.filter(_ != DontCare)
+ require(!filteredElts.isEmpty, s"can't create $createdType with only DontCare inputs")
+
+ if (filteredElts.head.isInstanceOf[Bits]) {
+ val model: T = filteredElts reduce { (elt1: T, elt2: T) => ((elt1, elt2) match {
+ case (elt1: Bool, elt2: Bool) => elt1
+ case (elt1: Bool, elt2: UInt) => elt2 // TODO: what happens with zero width UInts?
+ case (elt1: UInt, elt2: Bool) => elt1 // TODO: what happens with zero width UInts?
+ case (elt1: UInt, elt2: UInt) =>
+ // TODO: perhaps redefine Widths to allow >= op?
+ if (elt1.width == (elt1.width max elt2.width)) elt1 else elt2
+ case (elt1: SInt, elt2: SInt) => if (elt1.width == (elt1.width max elt2.width)) elt1 else elt2
+ case (elt1: FixedPoint, elt2: FixedPoint) => {
+ (elt1.binaryPoint, elt2.binaryPoint, elt1.width, elt2.width) match {
+ case (KnownBinaryPoint(bp1), KnownBinaryPoint(bp2), KnownWidth(w1), KnownWidth(w2)) =>
+ val maxBinaryPoint = bp1 max bp2
+ val maxIntegerWidth = (w1 - bp1) max (w2 - bp2)
+ FixedPoint((maxIntegerWidth + maxBinaryPoint).W, (maxBinaryPoint).BP)
+ case (KnownBinaryPoint(bp1), KnownBinaryPoint(bp2), _, _) =>
+ FixedPoint(Width(), (bp1 max bp2).BP)
+ case _ => FixedPoint()
+ }
+ }
+ case (elt1: Interval, elt2: Interval) =>
+ val range = if(elt1.range.width == elt1.range.width.max(elt2.range.width)) elt1.range else elt2.range
+ Interval(range)
+ case (elt1, elt2) =>
+ throw new AssertionError(
+ s"can't create $createdType with heterogeneous types ${elt1.getClass} and ${elt2.getClass}")
+ }).asInstanceOf[T] }
+ model.cloneTypeFull
+ }
+ else {
+ for (elt <- filteredElts.tail) {
+ require(elt.getClass == filteredElts.head.getClass,
+ s"can't create $createdType with heterogeneous types ${filteredElts.head.getClass} and ${elt.getClass}")
+ require(elt typeEquivalent filteredElts.head,
+ s"can't create $createdType with non-equivalent types ${filteredElts.head} and ${elt}")
+ }
+ filteredElts.head.cloneTypeFull
+ }
+ }
+}
+
+/** Returns the chisel type of a hardware object, allowing other hardware to be constructed from it.
+ */
+object chiselTypeOf {
+ def apply[T <: Data](target: T): T = {
+ requireIsHardware(target)
+ target.cloneTypeFull.asInstanceOf[T]
+ }
+}
+
+/**
+* Input, Output, and Flipped are used to define the directions of Module IOs.
+*
+* Note that they currently clone their source argument, including its bindings.
+*
+* Thus, an error will be thrown if these are used on bound Data
+*/
+object Input {
+ def apply[T<:Data](source: T)(implicit compileOptions: CompileOptions): T = {
+ SpecifiedDirection.specifiedDirection(source)(SpecifiedDirection.Input)
+ }
+}
+object Output {
+ def apply[T<:Data](source: T)(implicit compileOptions: CompileOptions): T = {
+ SpecifiedDirection.specifiedDirection(source)(SpecifiedDirection.Output)
+ }
+}
+
+object Flipped {
+ def apply[T<:Data](source: T)(implicit compileOptions: CompileOptions): T = {
+ SpecifiedDirection.specifiedDirection(source)(SpecifiedDirection.flip(source.specifiedDirection))
+ }
+}
+
+/** 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.
+ *
+ * @groupdesc Connect Utilities for connecting hardware components
+ * @define coll data
+ */
+abstract class Data extends HasId with NamedComponent with SourceInfoDoc { // scalastyle:ignore number.of.methods
+ // This is a bad API that punches through object boundaries.
+ @deprecated("pending removal once all instances replaced", "chisel3")
+ private[chisel3] def flatten: IndexedSeq[Element] = {
+ this match {
+ case elt: Aggregate => elt.getElements.toIndexedSeq flatMap {_.flatten}
+ case elt: Element => IndexedSeq(elt)
+ case elt => throwException(s"Cannot flatten type ${elt.getClass}")
+ }
+ }
+
+ // User-specified direction, local at this node only.
+ // Note that the actual direction of this node can differ from child and parent specifiedDirection.
+ private var _specifiedDirection: SpecifiedDirection = SpecifiedDirection.Unspecified
+ private[chisel3] def specifiedDirection: SpecifiedDirection = _specifiedDirection
+ private[chisel3] def specifiedDirection_=(direction: SpecifiedDirection) = {
+ if (_specifiedDirection != SpecifiedDirection.Unspecified) {
+ this match {
+ // Anything flies in compatibility mode
+ case t: Record if !t.compileOptions.dontAssumeDirectionality =>
+ case _ => throw RebindingException(s"Attempted reassignment of user-specified direction to $this")
+ }
+ }
+ _specifiedDirection = direction
+ }
+
+ /** This overwrites a relative SpecifiedDirection with an explicit one, and is used to implement
+ * the compatibility layer where, at the elements, Flip is Input and unspecified is Output.
+ * DO NOT USE OUTSIDE THIS PURPOSE. THIS OPERATION IS DANGEROUS!
+ */
+ private[chisel3] def _assignCompatibilityExplicitDirection: Unit = { // scalastyle:off method.name
+ (this, _specifiedDirection) match {
+ case (_: Analog, _) => // nothing to do
+ case (_, SpecifiedDirection.Unspecified) => _specifiedDirection = SpecifiedDirection.Output
+ case (_, SpecifiedDirection.Flip) => _specifiedDirection = SpecifiedDirection.Input
+ case (_, SpecifiedDirection.Input | SpecifiedDirection.Output) => // nothing to do
+ }
+ }
+
+ // Binding stores information about this node's position in the hardware graph.
+ // This information is supplemental (more than is necessary to generate FIRRTL) and is used to
+ // perform checks in Chisel, where more informative error messages are possible.
+ private var _binding: Option[Binding] = None
+ // Only valid after node is bound (synthesizable), crashes otherwise
+ protected[chisel3] def binding: Option[Binding] = _binding
+ protected def binding_=(target: Binding) {
+ if (_binding.isDefined) {
+ throw RebindingException(s"Attempted reassignment of binding to $this")
+ }
+ _binding = Some(target)
+ }
+
+ // Similar to topBindingOpt except it explicitly excludes SampleElements which are bound but not
+ // hardware
+ private[chisel3] final def isSynthesizable: Boolean = _binding.map {
+ case ChildBinding(parent) => parent.isSynthesizable
+ case _: TopBinding => true
+ case _: SampleElementBinding[_] => false
+ }.getOrElse(false)
+
+ private[chisel3] def topBindingOpt: Option[TopBinding] = _binding.flatMap {
+ case ChildBinding(parent) => parent.topBindingOpt
+ case bindingVal: TopBinding => Some(bindingVal)
+ case SampleElementBinding(parent) => parent.topBindingOpt
+ }
+
+ private[chisel3] def topBinding: TopBinding = topBindingOpt.get
+
+ /** Binds this node to the hardware graph.
+ * parentDirection is the direction of the parent node, or Unspecified (default) if the target
+ * node is the top-level.
+ * binding and direction are valid after this call completes.
+ */
+ private[chisel3] def bind(target: Binding, parentDirection: SpecifiedDirection = SpecifiedDirection.Unspecified)
+
+ // Both _direction and _resolvedUserDirection are saved versions of computed variables (for
+ // efficiency, avoid expensive recomputation of frequent operations).
+ // Both are only valid after binding is set.
+
+ // Direction of this node, accounting for parents (force Input / Output) and children.
+ private var _direction: Option[ActualDirection] = None
+
+ private[chisel3] def direction: ActualDirection = _direction.get
+ private[chisel3] def direction_=(actualDirection: ActualDirection) {
+ if (_direction.isDefined) {
+ throw RebindingException(s"Attempted reassignment of resolved direction to $this")
+ }
+ _direction = Some(actualDirection)
+ }
+
+ // User-friendly representation of the binding as a helper function for toString.
+ // Provides a unhelpful fallback for literals, which should have custom rendering per
+ // Data-subtype.
+ // TODO Is this okay for sample_element? It *shouldn't* be visible to users
+ protected def bindingToString: String = topBindingOpt match {
+ case None => ""
+ case Some(OpBinding(enclosure)) => s"(OpResult in ${enclosure.desiredName})"
+ case Some(MemoryPortBinding(enclosure)) => s"(MemPort in ${enclosure.desiredName})"
+ case Some(PortBinding(enclosure)) if !enclosure.isClosed => s"(IO in unelaborated ${enclosure.desiredName})"
+ case Some(PortBinding(enclosure)) if enclosure.isClosed =>
+ DataMirror.fullModulePorts(enclosure).find(_._2 eq this) match {
+ case Some((name, _)) => s"(IO $name in ${enclosure.desiredName})"
+ case None => s"(IO (unknown) in ${enclosure.desiredName})"
+ }
+ case Some(RegBinding(enclosure)) => s"(Reg in ${enclosure.desiredName})"
+ case Some(WireBinding(enclosure)) => s"(Wire in ${enclosure.desiredName})"
+ case Some(DontCareBinding()) => s"(DontCare)"
+ case Some(ElementLitBinding(litArg)) => s"(unhandled literal)"
+ case Some(BundleLitBinding(litMap)) => s"(unhandled bundle literal)"
+ }
+
+ // Return ALL elements at root of this type.
+ // Contasts with flatten, which returns just Bits
+ // TODO: refactor away this, this is outside the scope of Data
+ private[chisel3] def allElements: Seq[Element]
+
+ private[chisel3] def badConnect(that: Data)(implicit sourceInfo: SourceInfo): Unit =
+ throwException(s"cannot connect ${this} and ${that}")
+ private[chisel3] def connect(that: Data)(implicit sourceInfo: SourceInfo, connectCompileOptions: CompileOptions): Unit = { // scalastyle:ignore line.size.limit
+ if (connectCompileOptions.checkSynthesizable) {
+ requireIsHardware(this, "data to be connected")
+ requireIsHardware(that, "data to be connected")
+ this.topBinding match {
+ case _: ReadOnlyBinding => throwException(s"Cannot reassign to read-only $this")
+ case _ => // fine
+ }
+ try {
+ MonoConnect.connect(sourceInfo, connectCompileOptions, this, that, Builder.referenceUserModule)
+ } catch {
+ case MonoConnectException(message) =>
+ throwException(
+ s"Connection between sink ($this) and source ($that) failed @$message"
+ )
+ }
+ } else {
+ this legacyConnect that
+ }
+ }
+ private[chisel3] def bulkConnect(that: Data)(implicit sourceInfo: SourceInfo, connectCompileOptions: CompileOptions): Unit = { // scalastyle:ignore line.size.limit
+ if (connectCompileOptions.checkSynthesizable) {
+ requireIsHardware(this, s"data to be bulk-connected")
+ requireIsHardware(that, s"data to be bulk-connected")
+ (this.topBinding, that.topBinding) match {
+ case (_: ReadOnlyBinding, _: ReadOnlyBinding) => throwException(s"Both $this and $that are read-only")
+ // DontCare cannot be a sink (LHS)
+ case (_: DontCareBinding, _) => throw BiConnect.DontCareCantBeSink
+ case _ => // fine
+ }
+ try {
+ BiConnect.connect(sourceInfo, connectCompileOptions, this, that, Builder.referenceUserModule)
+ } catch {
+ case BiConnectException(message) =>
+ throwException(
+ s"Connection between left ($this) and source ($that) failed @$message"
+ )
+ }
+ } else {
+ this legacyConnect that
+ }
+ }
+
+ /** Whether this Data has the same model ("data type") as that Data.
+ * Data subtypes should overload this with checks against their own type.
+ */
+ private[chisel3] def typeEquivalent(that: Data): Boolean
+
+ // Internal API: returns a ref that can be assigned to, if consistent with the binding
+ private[chisel3] def lref: Node = {
+ requireIsHardware(this)
+ topBindingOpt match {
+ case Some(binding: ReadOnlyBinding) => throwException(s"internal error: attempted to generate LHS ref to ReadOnlyBinding $binding") // scalastyle:ignore line.size.limit
+ case Some(binding: TopBinding) => Node(this)
+ case opt => throwException(s"internal error: unknown binding $opt in generating LHS ref")
+ }
+ }
+
+
+ // Internal API: returns a ref, if bound. Literals should override this as needed.
+ private[chisel3] def ref: Arg = {
+ requireIsHardware(this)
+ topBindingOpt match {
+ case Some(binding: LitBinding) => throwException(s"internal error: can't handle literal binding $binding")
+ case Some(binding: TopBinding) => Node(this)
+ case opt => throwException(s"internal error: unknown binding $opt in generating LHS ref")
+ }
+ }
+
+ private[chisel3] def width: Width
+ private[chisel3] def legacyConnect(that: Data)(implicit sourceInfo: SourceInfo): Unit
+
+ /** Internal API; Chisel users should look at chisel3.chiselTypeOf(...).
+ *
+ * cloneType must be defined for any Chisel object extending Data.
+ * It is responsible for constructing a basic copy of the object being cloned.
+ *
+ * @return a copy of the object.
+ */
+ def cloneType: this.type
+
+ /** Internal API; Chisel users should look at chisel3.chiselTypeOf(...).
+ *
+ * Returns a copy of this data type, with hardware bindings (if any) removed.
+ * Directionality data is still preserved.
+ */
+ private[chisel3] def cloneTypeFull: this.type = {
+ val clone = this.cloneType.asInstanceOf[this.type] // get a fresh object, without bindings
+ // Only the top-level direction needs to be fixed up, cloneType should do the rest
+ clone.specifiedDirection = specifiedDirection
+ clone
+ }
+
+ /** Connect this $coll to that $coll mono-directionally and element-wise.
+ *
+ * This uses the [[MonoConnect]] algorithm.
+ *
+ * @param that the $coll to connect to
+ * @group Connect
+ */
+ final def := (that: Data)(implicit sourceInfo: SourceInfo, connectionCompileOptions: CompileOptions): Unit = this.connect(that)(sourceInfo, connectionCompileOptions) // scalastyle:ignore line.size.limit
+
+ /** Connect this $coll to that $coll bi-directionally and element-wise.
+ *
+ * This uses the [[BiConnect]] algorithm.
+ *
+ * @param that the $coll to connect to
+ * @group Connect
+ */
+ final def <> (that: Data)(implicit sourceInfo: SourceInfo, connectionCompileOptions: CompileOptions): Unit = this.bulkConnect(that)(sourceInfo, connectionCompileOptions) // scalastyle:ignore line.size.limit
+
+ @chiselRuntimeDeprecated
+ @deprecated("litArg is deprecated, use litOption or litTo*Option", "3.2")
+ def litArg(): Option[LitArg] = topBindingOpt match {
+ case Some(ElementLitBinding(litArg)) => Some(litArg)
+ case Some(BundleLitBinding(litMap)) => None // this API does not support Bundle literals
+ case _ => None
+ }
+
+ def isLit(): Boolean = litOption.isDefined
+
+ /**
+ * If this is a literal that is representable as bits, returns the value as a BigInt.
+ * If not a literal, or not representable as bits (for example, is or contains Analog), returns None.
+ */
+ def litOption(): Option[BigInt]
+
+ /**
+ * Returns the literal value if this is a literal that is representable as bits, otherwise crashes.
+ */
+ def litValue(): BigInt = litOption.get
+
+ /** Returns the width, in bits, if currently known. */
+ final def getWidth: Int =
+ if (isWidthKnown) width.get else throwException(s"Width of $this is unknown!")
+ /** Returns whether the width is currently known. */
+ final def isWidthKnown: Boolean = width.known
+ /** Returns Some(width) if the width is known, else None. */
+ final def widthOption: Option[Int] = if (isWidthKnown) Some(getWidth) else None
+
+ /** Does a reinterpret cast of the bits in this node into the format that provides.
+ * Returns a new Wire of that type. Does not modify existing nodes.
+ *
+ * x.asTypeOf(that) performs the inverse operation of x := that.toBits.
+ *
+ * @note bit widths are NOT checked, may pad or drop bits from input
+ * @note that should have known widths
+ */
+ def asTypeOf[T <: Data](that: T): T = macro SourceInfoTransform.thatArg
+
+ /** @group SourceInfoTransformMacro */
+ def do_asTypeOf[T <: Data](that: T)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): T = {
+ val thatCloned = Wire(that.cloneTypeFull)
+ thatCloned.connectFromBits(this.asUInt())
+ thatCloned
+ }
+
+ /** Assigns this node from Bits type. Internal implementation for asTypeOf.
+ */
+ private[chisel3] def connectFromBits(that: Bits)(implicit sourceInfo: SourceInfo,
+ compileOptions: CompileOptions): Unit
+
+ /** Reinterpret cast to UInt.
+ *
+ * @note value not guaranteed to be preserved: for example, a SInt of width
+ * 3 and value -1 (0b111) would become an UInt with value 7
+ * @note Aggregates are recursively packed with the first element appearing
+ * in the least-significant bits of the result.
+ */
+ final def asUInt(): UInt = macro SourceInfoTransform.noArg
+
+ /** @group SourceInfoTransformMacro */
+ def do_asUInt(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): UInt
+
+ /** Default pretty printing */
+ def toPrintable: Printable
+}
+
+trait WireFactory {
+ /** Construct a [[Wire]] from a type template
+ * @param t The template from which to construct this wire
+ */
+ def apply[T <: Data](t: T)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): T = {
+ if (compileOptions.declaredTypeMustBeUnbound) {
+ requireIsChiselType(t, "wire type")
+ }
+ val x = t.cloneTypeFull
+
+ // Bind each element of x to being a Wire
+ x.bind(WireBinding(Builder.forcedUserModule))
+
+ pushCommand(DefWire(sourceInfo, x))
+ if (!compileOptions.explicitInvalidate) {
+ pushCommand(DefInvalid(sourceInfo, x.ref))
+ }
+
+ x
+ }
+}
+
+/** Utility for constructing hardware wires
+ *
+ * The width of a `Wire` (inferred or not) is copied from the type template
+ * {{{
+ * val w0 = Wire(UInt()) // width is inferred
+ * val w1 = Wire(UInt(8.W)) // width is set to 8
+ *
+ * val w2 = Wire(Vec(4, UInt())) // width is inferred
+ * val w3 = Wire(Vec(4, UInt(8.W))) // width of each element is set to 8
+ *
+ * class MyBundle {
+ * val unknown = UInt()
+ * val known = UInt(8.W)
+ * }
+ * val w4 = Wire(new MyBundle)
+ * // Width of w4.unknown is inferred
+ * // Width of w4.known is set to 8
+ * }}}
+ *
+ */
+object Wire extends WireFactory
+
+/** Utility for constructing hardware wires with a default connection
+ *
+ * The two forms of `WireDefault` differ in how the type and width of the resulting [[Wire]] are
+ * specified.
+ *
+ * ==Single Argument==
+ * The single argument form uses the argument to specify both the type and default connection. For
+ * non-literal [[Bits]], the width of the [[Wire]] will be inferred. For literal [[Bits]] and all
+ * non-Bits arguments, the type will be copied from the argument. See the following examples for
+ * more details:
+ *
+ * 1. Literal [[Bits]] initializer: width will be set to match
+ * {{{
+ * val w1 = WireDefault(1.U) // width will be inferred to be 1
+ * val w2 = WireDefault(1.U(8.W)) // width is set to 8
+ * }}}
+ *
+ * 2. Non-Literal [[Element]] initializer - width will be inferred
+ * {{{
+ * val x = Wire(UInt())
+ * val y = Wire(UInt(8.W))
+ * val w1 = WireDefault(x) // width will be inferred
+ * val w2 = WireDefault(y) // width will be inferred
+ * }}}
+ *
+ * 3. [[Aggregate]] initializer - width will be set to match the aggregate
+ *
+ * {{{
+ * class MyBundle {
+ * val unknown = UInt()
+ * val known = UInt(8.W)
+ * }
+ * val w1 = Wire(new MyBundle)
+ * val w2 = WireDefault(w1)
+ * // Width of w2.unknown is inferred
+ * // Width of w2.known is set to 8
+ * }}}
+ *
+ * ==Double Argument==
+ * The double argument form allows the type of the [[Wire]] and the default connection to be
+ * specified independently.
+ *
+ * The width inference semantics for `WireDefault` with two arguments match those of [[Wire]]. The
+ * first argument to `WireDefault` is the type template which defines the width of the `Wire` in
+ * exactly the same way as the only argument to [[Wire]].
+ *
+ * More explicitly, you can reason about `WireDefault` with multiple arguments as if it were defined
+ * as:
+ * {{{
+ * def WireDefault[T <: Data](t: T, init: T): T = {
+ * val x = Wire(t)
+ * x := init
+ * x
+ * }
+ * }}}
+ *
+ * @note The `Default` in `WireDefault` refers to a `default` connection. This is in contrast to
+ * [[RegInit]] where the `Init` refers to a value on reset.
+ */
+object WireDefault {
+
+ private def applyImpl[T <: Data](t: T, init: Data)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): T = { // scalastyle:ignore line.size.limit
+ implicit val noSourceInfo = UnlocatableSourceInfo
+ val x = Wire(t)
+ requireIsHardware(init, "wire initializer")
+ x := init
+ x
+ }
+
+ /** Construct a [[Wire]] with a type template and a [[chisel3.DontCare]] default
+ * @param t The type template used to construct this [[Wire]]
+ * @param init The default connection to this [[Wire]], can only be [[DontCare]]
+ * @note This is really just a specialized form of `apply[T <: Data](t: T, init: T): T` with [[DontCare]] as `init`
+ */
+ def apply[T <: Data](t: T, init: DontCare.type)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): T = { // scalastyle:ignore line.size.limit
+ applyImpl(t, init)
+ }
+
+ /** Construct a [[Wire]] with a type template and a default connection
+ * @param t The type template used to construct this [[Wire]]
+ * @param init The hardware value that will serve as the default value
+ */
+ def apply[T <: Data](t: T, init: T)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): T = {
+ applyImpl(t, init)
+ }
+
+ /** Construct a [[Wire]] with a default connection
+ * @param init The hardware value that will serve as a type template and default value
+ */
+ def apply[T <: Data](init: T)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): T = {
+ val model = (init match {
+ // If init is a literal without forced width OR any non-literal, let width be inferred
+ case init: Bits if !init.litIsForcedWidth.getOrElse(false) => init.cloneTypeWidth(Width())
+ case _ => init.cloneTypeFull
+ }).asInstanceOf[T]
+ apply(model, init)
+ }
+}
+
+package internal {
+ /** RHS (source) for Invalidate API.
+ * Causes connection logic to emit a DefInvalid when connected to an output port (or wire).
+ */
+ private[chisel3] object InternalDontCare extends Element {
+ // This object should be initialized before we execute any user code that refers to it,
+ // otherwise this "Chisel" object will end up on the UserModule's id list.
+ // We make it private to chisel3 so it has to be accessed through the package object.
+
+ private[chisel3] override val width: Width = UnknownWidth()
+
+ bind(DontCareBinding(), SpecifiedDirection.Output)
+ override def cloneType: this.type = DontCare
+
+ override def toString: String = "DontCare()"
+
+ override def litOption: Option[BigInt] = None
+
+ def toPrintable: Printable = PString("DONTCARE")
+
+ private[chisel3] def connectFromBits(that: Bits)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Unit = { // scalastyle:ignore line.size.limit
+ Builder.error("connectFromBits: DontCare cannot be a connection sink (LHS)")
+ }
+
+ def do_asUInt(implicit sourceInfo: chisel3.internal.sourceinfo.SourceInfo, compileOptions: CompileOptions): UInt = { // scalastyle:ignore line.size.limit
+ Builder.error("DontCare does not have a UInt representation")
+ 0.U
+ }
+ // DontCare's only match themselves.
+ private[chisel3] def typeEquivalent(that: Data): Boolean = that == DontCare
+ }
+}
diff --git a/core/src/main/scala/chisel3/Element.scala b/core/src/main/scala/chisel3/Element.scala
new file mode 100644
index 00000000..fccae9ab
--- /dev/null
+++ b/core/src/main/scala/chisel3/Element.scala
@@ -0,0 +1,62 @@
+// See LICENSE for license details.
+
+package chisel3
+
+import chisel3.internal.Builder.pushCommand
+import chisel3.internal.firrtl._
+import chisel3.internal.sourceinfo.SourceInfo
+import chisel3.internal._
+
+/** Element is a leaf data type: it cannot contain other [[Data]] objects. Example uses are for representing primitive
+ * data types, like integers and bits.
+ *
+ * @define coll element
+ */
+abstract class Element extends Data {
+ private[chisel3] final def allElements: Seq[Element] = Seq(this)
+ def widthKnown: Boolean = width.known
+ def name: String = getRef.name
+
+ private[chisel3] override def bind(target: Binding, parentDirection: SpecifiedDirection) {
+ binding = target
+ val resolvedDirection = SpecifiedDirection.fromParent(parentDirection, specifiedDirection)
+ direction = ActualDirection.fromSpecified(resolvedDirection)
+ }
+
+ private[chisel3] override def topBindingOpt: Option[TopBinding] = super.topBindingOpt match {
+ // Translate Bundle lit bindings to Element lit bindings
+ case Some(BundleLitBinding(litMap)) => litMap.get(this) match {
+ case Some(litArg) => Some(ElementLitBinding(litArg))
+ case _ => Some(DontCareBinding())
+ }
+ case topBindingOpt => topBindingOpt
+ }
+
+ private[chisel3] def litArgOption: Option[LitArg] = topBindingOpt match {
+ case Some(ElementLitBinding(litArg)) => Some(litArg)
+ case _ => None
+ }
+
+ override def litOption: Option[BigInt] = litArgOption.map(_.num)
+ private[chisel3] def litIsForcedWidth: Option[Boolean] = litArgOption.map(_.forcedWidth)
+
+ // provide bits-specific literal handling functionality here
+ override private[chisel3] def ref: Arg = topBindingOpt match {
+ case Some(ElementLitBinding(litArg)) => litArg
+ case Some(BundleLitBinding(litMap)) => litMap.get(this) match {
+ case Some(litArg) => litArg
+ case _ => throwException(s"internal error: DontCare should be caught before getting ref")
+ }
+ case _ => super.ref
+ }
+
+ private[chisel3] def legacyConnect(that: Data)(implicit sourceInfo: SourceInfo): Unit = {
+ // If the source is a DontCare, generate a DefInvalid for the sink,
+ // otherwise, issue a Connect.
+ if (that == DontCare) {
+ pushCommand(DefInvalid(sourceInfo, Node(this)))
+ } else {
+ pushCommand(Connect(sourceInfo, Node(this), that.ref))
+ }
+ }
+}
diff --git a/core/src/main/scala/chisel3/Mem.scala b/core/src/main/scala/chisel3/Mem.scala
new file mode 100644
index 00000000..24ab4b8e
--- /dev/null
+++ b/core/src/main/scala/chisel3/Mem.scala
@@ -0,0 +1,216 @@
+// See LICENSE for license details.
+
+package chisel3
+
+import scala.language.experimental.macros
+
+import firrtl.{ir => fir}
+
+import chisel3.internal._
+import chisel3.internal.Builder.pushCommand
+import chisel3.internal.firrtl._
+import chisel3.internal.sourceinfo.{SourceInfo, SourceInfoTransform, UnlocatableSourceInfo, MemTransform}
+
+
+object Mem {
+
+ /** Creates a combinational/asynchronous-read, sequential/synchronous-write [[Mem]].
+ *
+ * @param size number of elements in the memory
+ * @param t data type of memory element
+ */
+ def apply[T <: Data](size: BigInt, t: T): Mem[T] = macro MemTransform.apply[T]
+
+ /** Creates a combinational/asynchronous-read, sequential/synchronous-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]
+
+ /** @group SourceInfoTransformMacro */
+ def do_apply[T <: Data](size: BigInt, t: T)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Mem[T] = {
+ if (compileOptions.declaredTypeMustBeUnbound) {
+ requireIsChiselType(t, "memory type")
+ }
+ val mt = t.cloneTypeFull
+ val mem = new Mem(mt, size)
+ pushCommand(DefMemory(sourceInfo, mem, mt, size))
+ mem
+ }
+
+ /** @group SourceInfoTransformMacro */
+ def do_apply[T <: Data](size: Int, t: T)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Mem[T] =
+ do_apply(BigInt(size), t)(sourceInfo, compileOptions)
+}
+
+sealed abstract class MemBase[T <: Data](val t: T, val length: BigInt) extends HasId with NamedComponent with SourceInfoDoc {
+ // 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(x: BigInt): T = macro SourceInfoTransform.xArg
+
+ /** Creates a read accessor into the memory with static addressing. See the
+ * class documentation of the memory for more detailed information.
+ */
+ def apply(x: Int): T = macro SourceInfoTransform.xArg
+
+ /** @group SourceInfoTransformMacro */
+ def do_apply(idx: BigInt)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): T = {
+ require(idx >= 0 && idx < length)
+ apply(idx.asUInt)
+ }
+
+ /** @group SourceInfoTransformMacro */
+ def do_apply(idx: Int)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): T =
+ do_apply(BigInt(idx))(sourceInfo, compileOptions)
+
+ /** Creates a read/write accessor into the memory with dynamic addressing.
+ * See the class documentation of the memory for more detailed information.
+ */
+ def apply(x: UInt): T = macro SourceInfoTransform.xArg
+
+ /** @group SourceInfoTransformMacro */
+ def do_apply(idx: UInt)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): T =
+ makePort(sourceInfo, 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(x: UInt): T = macro SourceInfoTransform.xArg
+
+ /** @group SourceInfoTransformMacro */
+ def do_read(idx: UInt)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): T =
+ makePort(sourceInfo, 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)(implicit compileOptions: CompileOptions): 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 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
+ */
+ def write(idx: UInt, data: T, mask: Seq[Bool]) (implicit evidence: T <:< Vec[_], compileOptions: CompileOptions): 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)(implicit compileOptions: CompileOptions): T = {
+ requireIsHardware(idx, "memory port index")
+ val i = Vec.truncateIndex(idx, length)(sourceInfo, compileOptions)
+
+ val port = pushCommand(
+ DefMemPort(sourceInfo,
+ t.cloneTypeFull, Node(this), dir, i.ref, Builder.forcedClock.ref)
+ ).id
+ // Bind each element of port to being a MemoryPort
+ port.bind(MemoryPortBinding(Builder.forcedUserModule))
+ port
+ }
+}
+
+/** A combinational/asynchronous-read, sequential/synchronous-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] private (t: T, length: BigInt) extends MemBase(t, length)
+
+object SyncReadMem {
+
+
+ type ReadUnderWrite = fir.ReadUnderWrite.Value
+ val Undefined = fir.ReadUnderWrite.Undefined
+ val ReadFirst = fir.ReadUnderWrite.Old
+ val WriteFirst = fir.ReadUnderWrite.New
+
+ /** Creates a sequential/synchronous-read, sequential/synchronous-write [[SyncReadMem]].
+ *
+ * @param size number of elements in the memory
+ * @param t data type of memory element
+ */
+ def apply[T <: Data](size: BigInt, t: T): SyncReadMem[T] = macro MemTransform.apply[T]
+ def apply[T <: Data](size: BigInt, t: T, ruw: ReadUnderWrite): SyncReadMem[T] = macro MemTransform.apply_ruw[T]
+
+ /** Creates a sequential/synchronous-read, sequential/synchronous-write [[SyncReadMem]].
+ *
+ * @param size number of elements in the memory
+ * @param t data type of memory element
+ */
+ def apply[T <: Data](size: Int, t: T): SyncReadMem[T] = macro MemTransform.apply[T]
+ def apply[T <: Data](size: Int, t: T, ruw: ReadUnderWrite): SyncReadMem[T] = macro MemTransform.apply_ruw[T]
+
+ /** @group SourceInfoTransformMacro */
+ def do_apply[T <: Data](size: BigInt, t: T, ruw: ReadUnderWrite = Undefined)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): SyncReadMem[T] = {
+ if (compileOptions.declaredTypeMustBeUnbound) {
+ requireIsChiselType(t, "memory type")
+ }
+ val mt = t.cloneTypeFull
+ val mem = new SyncReadMem(mt, size, ruw)
+ pushCommand(DefSeqMemory(sourceInfo, mem, mt, size, ruw))
+ mem
+ }
+
+ /** @group SourceInfoTransformMacro */
+ // Alternate signatures can't use default parameter values
+ def do_apply[T <: Data](size: Int, t: T)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): SyncReadMem[T] =
+ do_apply(BigInt(size), t)(sourceInfo, compileOptions)
+
+ /** @group SourceInfoTransformMacro */
+ // Alternate signatures can't use default parameter values
+ def do_apply[T <: Data](size: Int, t: T, ruw: ReadUnderWrite)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): SyncReadMem[T] =
+ do_apply(BigInt(size), t, ruw)(sourceInfo, compileOptions)
+}
+
+/** A sequential/synchronous-read, sequential/synchronous-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 SyncReadMem[T <: Data] private (t: T, n: BigInt, val readUnderWrite: SyncReadMem.ReadUnderWrite) extends MemBase[T](t, n) {
+ def read(x: UInt, en: Bool): T = macro SourceInfoTransform.xEnArg
+
+ /** @group SourceInfoTransformMacro */
+ def do_read(addr: UInt, enable: Bool)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): T = {
+ val a = Wire(UInt())
+ a := DontCare
+ var port: Option[T] = None
+ when (enable) {
+ a := addr
+ port = Some(read(a))
+ }
+ port.get
+ }
+}
diff --git a/core/src/main/scala/chisel3/Module.scala b/core/src/main/scala/chisel3/Module.scala
new file mode 100644
index 00000000..f1c4e30a
--- /dev/null
+++ b/core/src/main/scala/chisel3/Module.scala
@@ -0,0 +1,405 @@
+// See LICENSE for license details.
+
+package chisel3
+
+import scala.collection.immutable.ListMap
+import scala.collection.mutable.{ArrayBuffer, HashMap}
+import scala.collection.JavaConversions._
+import scala.language.experimental.macros
+
+import java.util.IdentityHashMap
+
+import chisel3.internal._
+import chisel3.internal.Builder._
+import chisel3.internal.firrtl._
+import chisel3.internal.sourceinfo.{InstTransform, SourceInfo}
+import chisel3.experimental.BaseModule
+import _root_.firrtl.annotations.{ModuleName, ModuleTarget, IsModule}
+
+object Module extends SourceInfoDoc {
+ /** A wrapper method that all Module instantiations must be wrapped in
+ * (necessary to help Chisel track internal state).
+ *
+ * @param bc the Module being created
+ *
+ * @return the input module `m` with Chisel metadata properly set
+ */
+ def apply[T <: BaseModule](bc: => T): T = macro InstTransform.apply[T]
+
+ /** @group SourceInfoTransformMacro */
+ def do_apply[T <: BaseModule](bc: => T)
+ (implicit sourceInfo: SourceInfo,
+ compileOptions: CompileOptions): T = {
+ if (Builder.readyForModuleConstr) {
+ throwException("Error: Called Module() twice without instantiating a Module." +
+ sourceInfo.makeMessage(" See " + _))
+ }
+ Builder.readyForModuleConstr = true
+
+ val parent = Builder.currentModule
+ val whenDepth: Int = Builder.whenDepth
+
+ // Save then clear clock and reset to prevent leaking scope, must be set again in the Module
+ val (saveClock, saveReset) = (Builder.currentClock, Builder.currentReset)
+ Builder.currentClock = None
+ Builder.currentReset = None
+
+ // Execute the module, this has the following side effects:
+ // - set currentModule
+ // - unset readyForModuleConstr
+ // - reset whenDepth to 0
+ // - set currentClockAndReset
+ val module: T = bc // bc is actually evaluated here
+
+ if (Builder.whenDepth != 0) {
+ throwException("Internal Error! when() scope depth is != 0, this should have been caught!")
+ }
+ if (Builder.readyForModuleConstr) {
+ throwException("Error: attempted to instantiate a Module, but nothing happened. " +
+ "This is probably due to rewrapping a Module instance with Module()." +
+ sourceInfo.makeMessage(" See " + _))
+ }
+ Builder.currentModule = parent // Back to parent!
+ Builder.whenDepth = whenDepth
+ Builder.currentClock = saveClock // Back to clock and reset scope
+ Builder.currentReset = saveReset
+
+ val component = module.generateComponent()
+ Builder.components += component
+
+ // Handle connections at enclosing scope
+ if(!Builder.currentModule.isEmpty) {
+ pushCommand(DefInstance(sourceInfo, module, component.ports))
+ module.initializeInParent(compileOptions)
+ }
+ module
+ }
+
+ /** Returns the implicit Clock */
+ def clock: Clock = Builder.forcedClock
+ /** Returns the implicit Reset */
+ def reset: Reset = Builder.forcedReset
+ /** Returns the current Module */
+ def currentModule: Option[BaseModule] = Builder.currentModule
+}
+
+package experimental {
+
+ object IO {
+ /** Constructs a port for the current Module
+ *
+ * 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 must be a chisel type and not be bound to hardware.
+ *
+ * Also registers a Data as a port, also performing bindings. Cannot be called once ports are
+ * requested (so that all calls to ports will return the same information).
+ * Internal API.
+ */
+ def apply[T<:Data](iodef: T): T = {
+ val module = Module.currentModule.get // Impossible to fail
+ require(!module.isClosed, "Can't add more ports after module close")
+ requireIsChiselType(iodef, "io type")
+
+ // Clone the IO so we preserve immutability of data types
+ val iodefClone = try {
+ iodef.cloneTypeFull
+ } catch {
+ // For now this is going to be just a deprecation so we don't suddenly break everyone's code
+ case e: AutoClonetypeException =>
+ Builder.deprecated(e.getMessage, Some(s"${iodef.getClass}"))
+ iodef
+ }
+ module.bindIoInPlace(iodefClone)
+ iodefClone
+ }
+ }
+}
+
+package internal {
+ import chisel3.experimental.BaseModule
+
+ object BaseModule {
+ private[chisel3] class ClonePorts (elts: Data*)(implicit compileOptions: CompileOptions) extends Record {
+ val elements = ListMap(elts.map(d => d.instanceName -> d.cloneTypeFull): _*)
+ def apply(field: String) = elements(field)
+ override def cloneType = (new ClonePorts(elts: _*)).asInstanceOf[this.type]
+ }
+
+ private[chisel3] def cloneIORecord(proto: BaseModule)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): ClonePorts = {
+ require(proto.isClosed, "Can't clone a module before module close")
+ val clonePorts = new ClonePorts(proto.getModulePorts: _*)
+ clonePorts.bind(WireBinding(Builder.forcedUserModule))
+ val cloneInstance = new DefInstance(sourceInfo, proto, proto._component.get.ports) {
+ override def name = clonePorts.getRef.name
+ }
+ pushCommand(cloneInstance)
+ if (!compileOptions.explicitInvalidate) {
+ pushCommand(DefInvalid(sourceInfo, clonePorts.ref))
+ }
+ if (proto.isInstanceOf[MultiIOModule]) {
+ clonePorts("clock") := Module.clock
+ clonePorts("reset") := Module.reset
+ }
+ clonePorts
+ }
+ }
+}
+
+package experimental {
+
+ /** Abstract base class for Modules, an instantiable organizational unit for RTL.
+ */
+ // TODO: seal this?
+ abstract class BaseModule extends HasId {
+ //
+ // Builder Internals - this tracks which Module RTL construction belongs to.
+ //
+ if (!Builder.readyForModuleConstr) {
+ throwException("Error: attempted to instantiate a Module without wrapping it in Module().")
+ }
+ readyForModuleConstr = false
+
+ Builder.currentModule = Some(this)
+ Builder.whenDepth = 0
+
+ //
+ // Module Construction Internals
+ //
+ protected var _closed = false
+
+ /** Internal check if a Module is closed */
+ private[chisel3] def isClosed = _closed
+
+ // Fresh Namespace because in Firrtl, Modules namespaces are disjoint with the global namespace
+ private[chisel3] val _namespace = Namespace.empty
+ private val _ids = ArrayBuffer[HasId]()
+ private[chisel3] def addId(d: HasId) {
+ if (Builder.aspectModule(this).isDefined) {
+ aspectModule(this).get.addId(d)
+ } else {
+ require(!_closed, "Can't write to module after module close")
+ _ids += d
+ }
+ }
+
+ protected def getIds = {
+ require(_closed, "Can't get ids before module close")
+ _ids.toSeq
+ }
+
+ private val _ports = new ArrayBuffer[Data]()
+
+ // getPorts unfortunately already used for tester compatibility
+ protected[chisel3] def getModulePorts = {
+ require(_closed, "Can't get ports before module close")
+ _ports.toSeq
+ }
+
+ // These methods allow checking some properties of ports before the module is closed,
+ // mainly for compatibility purposes.
+ protected def portsContains(elem: Data): Boolean = _ports contains elem
+
+ protected def portsSize: Int = _ports.size
+
+ /** Generates the FIRRTL Component (Module or Blackbox) of this Module.
+ * Also closes the module so no more construction can happen inside.
+ */
+ private[chisel3] def generateComponent(): Component
+
+ /** Sets up this module in the parent context
+ */
+ private[chisel3] def initializeInParent(parentCompileOptions: CompileOptions): Unit
+
+ //
+ // Chisel Internals
+ //
+
+ /** The desired name of this module (which will be used in generated FIRRTL IR or Verilog).
+ *
+ * The name of a module approximates the behavior of the Java Reflection [[`getSimpleName` method
+ * https://docs.oracle.com/javase/8/docs/api/java/lang/Class.html#getSimpleName--]] with some modifications:
+ *
+ * - Anonymous modules will get an `"_Anon"` tag
+ * - Modules defined in functions will use their class name and not a numeric name
+ *
+ * @note If you want a custom or parametric name, override this method.
+ */
+ def desiredName: String = {
+ /* The default module name is derived from the Java reflection derived class name. */
+ val baseName = this.getClass.getName
+
+ /* A sequence of string filters applied to the name */
+ val filters: Seq[String => String] = Seq(
+ ((a: String) => raw"\$$+anon".r.replaceAllIn(a, "_Anon")) // Merge the "$$anon" name with previous name
+ )
+
+ filters
+ .foldLeft(baseName){ case (str, filter) => filter(str) } // 1. Apply filters to baseName
+ .split("\\.|\\$") // 2. Split string at '.' or '$'
+ .filterNot(_.forall(_.isDigit)) // 3. Drop purely numeric names
+ .last // 4. Use the last name
+ }
+
+ /** Legalized name of this module. */
+ final lazy val name = try {
+ Builder.globalNamespace.name(desiredName)
+ } catch {
+ case e: NullPointerException => throwException(
+ s"Error: desiredName of ${this.getClass.getName} is null. Did you evaluate 'name' before all values needed by desiredName were available?", e) // scalastyle:ignore line.size.limit
+ case t: Throwable => throw t
+ }
+
+ /** Returns a FIRRTL ModuleName that references this object
+ *
+ * @note Should not be called until circuit elaboration is complete
+ */
+ final def toNamed: ModuleName = toTarget.toNamed
+
+ /** Returns a FIRRTL ModuleTarget that references this object
+ *
+ * @note Should not be called until circuit elaboration is complete
+ */
+ final def toTarget: ModuleTarget = ModuleTarget(this.circuitName, this.name)
+
+ /** Returns a FIRRTL ModuleTarget that references this object
+ *
+ * @note Should not be called until circuit elaboration is complete
+ */
+ final def toAbsoluteTarget: IsModule = {
+ _parent match {
+ case Some(parent) => parent.toAbsoluteTarget.instOf(this.instanceName, toTarget.module)
+ case None => toTarget
+ }
+ }
+
+ /**
+ * Internal API. Returns a list of this module's generated top-level ports as a map of a String
+ * (FIRRTL name) to the IO object. Only valid after the module is closed.
+ *
+ * Note: for BlackBoxes (but not ExtModules), this returns the contents of the top-level io
+ * object, consistent with what is emitted in FIRRTL.
+ *
+ * TODO: Use SeqMap/VectorMap when those data structures become available.
+ */
+ private[chisel3] def getChiselPorts: Seq[(String, Data)] = {
+ require(_closed, "Can't get ports before module close")
+ _component.get.ports.map { port =>
+ (port.id.getRef.asInstanceOf[ModuleIO].name, port.id)
+ }
+ }
+
+ /** Called at the Module.apply(...) level after this Module has finished elaborating.
+ * Returns a map of nodes -> names, for named nodes.
+ *
+ * Helper method.
+ */
+ protected def nameIds(rootClass: Class[_]): HashMap[HasId, String] = {
+ val names = new HashMap[HasId, String]()
+
+ def name(node: HasId, name: String) {
+ // First name takes priority, like suggestName
+ // TODO: DRYify with suggestName
+ if (!names.contains(node)) {
+ names.put(node, name)
+ }
+ }
+
+ /** Scala generates names like chisel3$util$Queue$$ram for private vals
+ * This extracts the part after $$ for names like this and leaves names
+ * without $$ unchanged
+ */
+ def cleanName(name: String): String = name.split("""\$\$""").lastOption.getOrElse(name)
+
+ for (m <- getPublicFields(rootClass)) {
+ Builder.nameRecursively(cleanName(m.getName), m.invoke(this), name)
+ }
+
+ names
+ }
+
+ /** Compatibility function. Allows Chisel2 code which had ports without the IO wrapper to
+ * compile under Bindings checks. Does nothing in non-compatibility mode.
+ *
+ * Should NOT be used elsewhere. This API will NOT last.
+ *
+ * TODO: remove this, perhaps by removing Bindings checks in compatibility mode.
+ */
+ def _compatAutoWrapPorts() {} // scalastyle:ignore method.name
+
+ /** Chisel2 code didn't require the IO(...) wrapper and would assign a Chisel type directly to
+ * io, then do operations on it. This binds a Chisel type in-place (mutably) as an IO.
+ */
+ protected def _bindIoInPlace(iodef: Data): Unit = { // scalastyle:ignore method.name
+ // Compatibility code: Chisel2 did not require explicit direction on nodes
+ // (unspecified treated as output, and flip on nothing was input).
+ // This sets assigns the explicit directions required by newer semantics on
+ // Bundles defined in compatibility mode.
+ // This recursively walks the tree, and assigns directions if no explicit
+ // direction given by upper-levels (override Input / Output) AND element is
+ // directly inside a compatibility Bundle determined by compile options.
+ def assignCompatDir(data: Data, insideCompat: Boolean): Unit = {
+ data match {
+ case data: Element if insideCompat => data._assignCompatibilityExplicitDirection
+ case data: Element => // Not inside a compatibility Bundle, nothing to be done
+ case data: Aggregate => data.specifiedDirection match {
+ // Recurse into children to ensure explicit direction set somewhere
+ case SpecifiedDirection.Unspecified | SpecifiedDirection.Flip => data match {
+ case record: Record =>
+ val compatRecord = !record.compileOptions.dontAssumeDirectionality
+ record.getElements.foreach(assignCompatDir(_, compatRecord))
+ case vec: Vec[_] =>
+ vec.getElements.foreach(assignCompatDir(_, insideCompat))
+ }
+ case SpecifiedDirection.Input | SpecifiedDirection.Output => // forced assign, nothing to do
+ }
+ }
+ }
+
+ assignCompatDir(iodef, false)
+
+ iodef.bind(PortBinding(this))
+ _ports += iodef
+ }
+
+ /** Private accessor for _bindIoInPlace */
+ private[chisel3] def bindIoInPlace(iodef: Data): Unit = _bindIoInPlace(iodef)
+
+ /**
+ * 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 must be a chisel type and not be bound to hardware.
+ *
+ * Also registers a Data as a port, also performing bindings. Cannot be called once ports are
+ * requested (so that all calls to ports will return the same information).
+ * Internal API.
+ *
+ * TODO(twigg): Specifically walk the Data definition to call out which nodes
+ * are problematic.
+ */
+ protected def IO[T <: Data](iodef: T): T = chisel3.experimental.IO.apply(iodef) // scalastyle:ignore method.name
+
+ //
+ // Internal Functions
+ //
+
+ /** Keep component for signal names */
+ private[chisel3] var _component: Option[Component] = None
+
+ /** Signal name (for simulation). */
+ override def instanceName: String =
+ if (_parent == None) name else _component match {
+ case None => getRef.name
+ case Some(c) => getRef fullName c
+ }
+
+ }
+}
diff --git a/core/src/main/scala/chisel3/ModuleAspect.scala b/core/src/main/scala/chisel3/ModuleAspect.scala
new file mode 100644
index 00000000..20793cd7
--- /dev/null
+++ b/core/src/main/scala/chisel3/ModuleAspect.scala
@@ -0,0 +1,26 @@
+// See LICENSE for license details.
+
+package chisel3
+
+import chisel3.internal.Builder
+
+/** Used by Chisel Aspects to inject Chisel code into modules, after they have been elaborated.
+ * This is an internal API - don't use!
+ *
+ * It adds itself as an aspect to the module, which allows proper checking of connection and binding legality.
+ *
+ * @param module Module for which this object is an aspect of
+ * @param moduleCompileOptions
+ */
+abstract class ModuleAspect private[chisel3] (module: RawModule)
+ (implicit moduleCompileOptions: CompileOptions) extends RawModule {
+
+ Builder.addAspect(module, this)
+
+ override def circuitName: String = module.toTarget.circuit
+
+ override def desiredName: String = module.name
+
+ override val _namespace = module._namespace
+}
+
diff --git a/core/src/main/scala/chisel3/MultiClock.scala b/core/src/main/scala/chisel3/MultiClock.scala
new file mode 100644
index 00000000..239e745a
--- /dev/null
+++ b/core/src/main/scala/chisel3/MultiClock.scala
@@ -0,0 +1,70 @@
+// See LICENSE for license details.
+
+package chisel3
+
+import chisel3.internal._
+
+import scala.language.experimental.macros
+
+object withClockAndReset { // scalastyle:ignore object.name
+ /** Creates a new Clock and Reset scope
+ *
+ * @param clock the new implicit Clock
+ * @param reset the new implicit Reset
+ * @param block the block of code to run with new implicit Clock and Reset
+ * @return the result of the block
+ */
+ def apply[T](clock: Clock, reset: Reset)(block: => T): T = {
+ // Save parentScope
+ val parentClock = Builder.currentClock
+ val parentReset = Builder.currentReset
+
+ Builder.currentClock = Some(clock)
+ Builder.currentReset = Some(reset)
+
+ val res = block // execute block
+
+ // Return to old scope
+ Builder.currentClock = parentClock
+ Builder.currentReset = parentReset
+ res
+ }
+}
+
+object withClock { // scalastyle:ignore object.name
+ /** Creates a new Clock scope
+ *
+ * @param clock the new implicit Clock
+ * @param block the block of code to run with new implicit Clock
+ * @return the result of the block
+ */
+ def apply[T](clock: Clock)(block: => T): T = {
+ // Save parentScope
+ val parentClock = Builder.currentClock
+ Builder.currentClock = Some(clock)
+ val res = block // execute block
+ // Return to old scope
+ Builder.currentClock = parentClock
+ res
+ }
+}
+
+object withReset { // scalastyle:ignore object.name
+ /** Creates a new Reset scope
+ *
+ * @param reset the new implicit Reset
+ * @param block the block of code to run with new implicit Reset
+ * @return the result of the block
+ */
+ def apply[T](reset: Reset)(block: => T): T = {
+ // Save parentScope
+ val parentReset = Builder.currentReset
+ Builder.currentReset = Some(reset)
+ val res = block // execute block
+ // Return to old scope
+ Builder.currentReset = parentReset
+ res
+ }
+
+}
+
diff --git a/core/src/main/scala/chisel3/Mux.scala b/core/src/main/scala/chisel3/Mux.scala
new file mode 100644
index 00000000..960424bf
--- /dev/null
+++ b/core/src/main/scala/chisel3/Mux.scala
@@ -0,0 +1,50 @@
+// See LICENSE for license details.
+
+package chisel3
+
+import scala.language.experimental.macros
+
+import chisel3.internal._
+import chisel3.internal.Builder.pushOp
+import chisel3.internal.sourceinfo.{SourceInfo, MuxTransform}
+import chisel3.internal.firrtl._
+import chisel3.internal.firrtl.PrimOp._
+
+object Mux extends SourceInfoDoc {
+ /** 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 === 3.U, 3.U(4.W), 0.U(4.W))
+ * }}}
+ */
+ def apply[T <: Data](cond: Bool, con: T, alt: T): T = macro MuxTransform.apply[T]
+
+ /** @group SourceInfoTransformMacro */
+ def do_apply[T <: Data](cond: Bool, con: T, alt: T)(implicit sourceInfo: SourceInfo,
+ compileOptions: CompileOptions): T = {
+ requireIsHardware(cond, "mux condition")
+ requireIsHardware(con, "mux true value")
+ requireIsHardware(alt, "mux false value")
+ val d = cloneSupertype(Seq(con, alt), "Mux")
+ val conRef = con match { // this matches chisel semantics (DontCare as object) to firrtl semantics (invalidate)
+ case DontCare =>
+ val dcWire = Wire(d)
+ dcWire := DontCare
+ dcWire.ref
+ case _ => con.ref
+ }
+ val altRef = alt match {
+ case DontCare =>
+ val dcWire = Wire(d)
+ dcWire := DontCare
+ dcWire.ref
+ case _ => alt.ref
+ }
+ pushOp(DefPrim(sourceInfo, d, MultiplexOp, cond.ref, conRef, altRef))
+ }
+}
diff --git a/core/src/main/scala/chisel3/Num.scala b/core/src/main/scala/chisel3/Num.scala
new file mode 100644
index 00000000..7a6b0744
--- /dev/null
+++ b/core/src/main/scala/chisel3/Num.scala
@@ -0,0 +1,308 @@
+// See LICENSE for license details.
+
+package chisel3
+
+import chisel3.internal.ChiselException
+import chisel3.internal.firrtl.{BinaryPoint, KnownBinaryPoint}
+
+import scala.language.experimental.macros
+import chisel3.internal.sourceinfo.{SourceInfo, SourceInfoTransform}
+
+// scalastyle:off method.name
+
+// REVIEW TODO: Further discussion needed on what Num actually is.
+
+/** Abstract trait defining operations available on numeric-like hardware data types.
+ *
+ * @tparam T the underlying type of the number
+ * @groupdesc Arithmetic Arithmetic hardware operators
+ * @groupdesc Comparison Comparison hardware operators
+ * @groupdesc Logical Logical hardware operators
+ * @define coll numeric-like type
+ * @define numType hardware type
+ * @define canHaveHighCost can result in significant cycle time and area costs
+ * @define canGenerateA This method generates a
+ * @define singleCycleMul @note $canGenerateA fully combinational multiplier which $canHaveHighCost.
+ * @define singleCycleDiv @note $canGenerateA fully combinational divider which $canHaveHighCost.
+ * @define maxWidth @note The width of the returned $numType is `max(width of this, width of that)`.
+ * @define maxWidthPlusOne @note The width of the returned $numType is `max(width of this, width of that) + 1`.
+ * @define sumWidth @note The width of the returned $numType is `width of this` + `width of that`.
+ * @define unchangedWidth @note The width of the returned $numType is unchanged, i.e., the `width of this`.
+ */
+trait Num[T <: Data] {
+ self: Num[T] =>
+ // def << (b: T): T
+ // def >> (b: T): T
+ //def unary_-(): T
+
+ // REVIEW TODO: double check ops conventions against FIRRTL
+
+ /** Addition operator
+ *
+ * @param that a $numType
+ * @return the sum of this $coll and `that`
+ * $maxWidth
+ * @group Arithmetic
+ */
+ final def + (that: T): T = macro SourceInfoTransform.thatArg
+
+ /** @group SourceInfoTransformMacro */
+ def do_+ (that: T)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): T
+
+ /** Multiplication operator
+ *
+ * @param that a $numType
+ * @return the product of this $coll and `that`
+ * $sumWidth
+ * $singleCycleMul
+ * @group Arithmetic
+ */
+ final def * (that: T): T = macro SourceInfoTransform.thatArg
+
+ /** @group SourceInfoTransformMacro */
+ def do_* (that: T)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): T
+
+ /** Division operator
+ *
+ * @param that a $numType
+ * @return the quotient of this $coll divided by `that`
+ * $singleCycleDiv
+ * @todo full rules
+ * @group Arithmetic
+ */
+ final def / (that: T): T = macro SourceInfoTransform.thatArg
+
+ /** @group SourceInfoTransformMacro */
+ def do_/ (that: T)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): T
+
+ /** Modulo operator
+ *
+ * @param that a $numType
+ * @return the remainder of this $coll divided by `that`
+ * $singleCycleDiv
+ * @group Arithmetic
+ */
+ final def % (that: T): T = macro SourceInfoTransform.thatArg
+
+ /** @group SourceInfoTransformMacro */
+ def do_% (that: T)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): T
+
+ /** Subtraction operator
+ *
+ * @param that a $numType
+ * @return the difference of this $coll less `that`
+ * $maxWidthPlusOne
+ * @group Arithmetic
+ */
+ final def - (that: T): T = macro SourceInfoTransform.thatArg
+
+ /** @group SourceInfoTransformMacro */
+ def do_- (that: T)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): T
+
+ /** Less than operator
+ *
+ * @param that a $numType
+ * @return a hardware [[Bool]] asserted if this $coll is less than `that`
+ * @group Comparison
+ */
+ final def < (that: T): Bool = macro SourceInfoTransform.thatArg
+
+ /** @group SourceInfoTransformMacro */
+ def do_< (that: T)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Bool
+
+ /** Less than or equal to operator
+ *
+ * @param that a $numType
+ * @return a hardware [[Bool]] asserted if this $coll is less than or equal to `that`
+ * @group Comparison
+ */
+ final def <= (that: T): Bool = macro SourceInfoTransform.thatArg
+
+ /** @group SourceInfoTransformMacro */
+ def do_<= (that: T)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Bool
+
+ /** Greater than operator
+ *
+ * @param that a hardware component
+ * @return a hardware [[Bool]] asserted if this $coll is greater than `that`
+ * @group Comparison
+ */
+ final def > (that: T): Bool = macro SourceInfoTransform.thatArg
+
+ /** @group SourceInfoTransformMacro */
+ def do_> (that: T)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Bool
+
+ /** Greater than or equal to operator
+ *
+ * @param that a hardware component
+ * @return a hardware [[Bool]] asserted if this $coll is greather than or equal to `that`
+ * @group Comparison
+ */
+ final def >= (that: T): Bool = macro SourceInfoTransform.thatArg
+
+ /** @group SourceInfoTransformMacro */
+ def do_>= (that: T)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Bool
+
+ /** Absolute value operator
+ *
+ * @return a $numType with a value equal to the absolute value of this $coll
+ * $unchangedWidth
+ * @group Arithmetic
+ */
+ final def abs(): T = macro SourceInfoTransform.noArg
+
+ /** @group SourceInfoTransformMacro */
+ def do_abs(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): T
+
+ /** Minimum operator
+ *
+ * @param that a hardware $coll
+ * @return a $numType with a value equal to the mimimum value of this $coll and `that`
+ * $maxWidth
+ * @group Arithmetic
+ */
+ final def min(that: T): T = macro SourceInfoTransform.thatArg
+
+ /** @group SourceInfoTransformMacro */
+ def do_min(that: T)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): T =
+ Mux(this < that, this.asInstanceOf[T], that)
+
+ /** Maximum operator
+ *
+ * @param that a $numType
+ * @return a $numType with a value equal to the mimimum value of this $coll and `that`
+ * $maxWidth
+ * @group Arithmetic
+ */
+ final def max(that: T): T = macro SourceInfoTransform.thatArg
+
+ /** @group SourceInfoTransformMacro */
+ def do_max(that: T)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): T =
+ Mux(this < that, that, this.asInstanceOf[T])
+}
+
+object Num extends NumObject
+
+/** NumbObject has a lot of convenience methods for converting between
+ * BigInts and Double and BigDecimal
+ * For backwards compatibility this is used with FixedPoint and Interval objects
+ * but is better used with the Num Object
+ *
+ */
+trait NumObject {
+ val MaxBitsBigIntToBigDecimal = 108
+ val MaxBitsBigIntToDouble = 53
+
+ /**
+ * How to create a bigint from a double with a specific binaryPoint
+ * @param x a double value
+ * @param binaryPoint a binaryPoint that you would like to use
+ * @return
+ */
+ def toBigInt(x: Double, binaryPoint: Int): BigInt = {
+ val multiplier = math.pow(2, binaryPoint)
+ val result = BigInt(math.round(x * multiplier))
+ result
+ }
+
+ /**
+ * How to create a bigint from a big decimal with a specific binaryPoint
+ * @param x a BigDecimal value
+ * @param binaryPoint a binaryPoint that you would like to use
+ * @return
+ */
+ def toBigInt(x: Double, binaryPoint: BinaryPoint): BigInt = {
+ binaryPoint match {
+ case KnownBinaryPoint(n) => toBigInt(x, n)
+ case x =>
+ throw new ChiselException(s"Error converting Double $x to BigInt, binary point must be known, not $x")
+ }
+ }
+
+ /**
+ * How to create a bigint from a big decimal with a specific binaryPoint (int)
+ * @param x a BigDecimal value
+ * @param binaryPoint a binaryPoint that you would like to use
+ * @return
+ */
+ def toBigInt(x: BigDecimal, binaryPoint: Int): BigInt = {
+ val multiplier = math.pow(2, binaryPoint)
+ val result = (x * multiplier).rounded.toBigInt()
+ result
+ }
+
+ /**
+ * How to create a bigint from a big decimal with a specific binaryPoint
+ * @param value a BigDecimal value
+ * @param binaryPoint a binaryPoint that you would like to use
+ * @return
+ */
+ def toBigInt(value: BigDecimal, binaryPoint: BinaryPoint): BigInt = {
+ binaryPoint match {
+ case KnownBinaryPoint(n) => toBigInt(value, n)
+ case x =>
+ throw new ChiselException(s"Error converting BigDecimal $value to BigInt, binary point must be known, not $x")
+ }
+ }
+
+ /**
+ * converts a bigInt with the given binaryPoint into the double representation
+ * @param i a bigint
+ * @param binaryPoint the implied binaryPoint of @i
+ * @return
+ */
+ def toDouble(i: BigInt, binaryPoint: Int): Double = {
+ if(i.bitLength >= 54) {
+ throw new ChiselException(
+ s"BigInt $i with bitlength ${i.bitLength} is too big, precision lost with > $MaxBitsBigIntToDouble bits"
+ )
+ }
+ val multiplier = math.pow(2, binaryPoint)
+ val result = i.toDouble / multiplier
+ result
+ }
+
+ /**
+ * converts a bigInt with the given binaryPoint into the double representation
+ * @param value a bigint
+ * @param binaryPoint the implied binaryPoint of @i
+ * @return
+ */
+ def toDouble(value: BigInt, binaryPoint: BinaryPoint): Double = {
+ binaryPoint match {
+ case KnownBinaryPoint(n) => toDouble(value, n)
+ case x =>
+ throw new ChiselException(s"Error converting BigDecimal $value to BigInt, binary point must be known, not $x")
+ } }
+
+ /**
+ * converts a bigInt with the given binaryPoint into the BigDecimal representation
+ * @param value a bigint
+ * @param binaryPoint the implied binaryPoint of @i
+ * @return
+ */
+ def toBigDecimal(value: BigInt, binaryPoint: Int): BigDecimal = {
+ if(value.bitLength > MaxBitsBigIntToBigDecimal) {
+ throw new ChiselException(
+ s"BigInt $value with bitlength ${value.bitLength} is too big, precision lost with > $MaxBitsBigIntToBigDecimal bits"
+ )
+ }
+ val multiplier = BigDecimal(1.0) / BigDecimal(math.pow(2, binaryPoint))
+ val result = BigDecimal(value) * multiplier
+ result
+ }
+
+ /**
+ * converts a bigInt with the given binaryPoint into the BigDecimal representation
+ * @param value a bigint
+ * @param binaryPoint the implied binaryPoint of @i
+ * @return
+ */
+ def toBigDecimal(value: BigInt, binaryPoint: BinaryPoint): BigDecimal = {
+ binaryPoint match {
+ case KnownBinaryPoint(n) => toBigDecimal(value, n)
+ case x =>
+ throw new ChiselException(s"Error converting BigDecimal $value to BigInt, binary point must be known, not $x")
+ }
+ }
+} \ No newline at end of file
diff --git a/core/src/main/scala/chisel3/Printable.scala b/core/src/main/scala/chisel3/Printable.scala
new file mode 100644
index 00000000..7add9166
--- /dev/null
+++ b/core/src/main/scala/chisel3/Printable.scala
@@ -0,0 +1,178 @@
+// See LICENSE for license details.
+
+package chisel3
+
+import chisel3.internal.firrtl.Component
+
+import scala.collection.mutable
+
+import java.util.{
+ MissingFormatArgumentException,
+ UnknownFormatConversionException
+}
+
+/** Superclass of things that can be printed in the resulting circuit
+ *
+ * Usually created using the custom string interpolator `p"..."`. Printable string interpolation is
+ * similar to [[https://docs.scala-lang.org/overviews/core/string-interpolation.html String
+ * interpolation in Scala]] For example:
+ * {{{
+ * printf(p"The value of wire = \$wire\n")
+ * }}}
+ * This is equivalent to writing:
+ * {{{
+ * printf(p"The value of wire = %d\n", wire)
+ * }}}
+ * All Chisel data types have a method `.toPrintable` that gives a default pretty print that can be
+ * accessed via `p"..."`. This works even for aggregate types, for example:
+ * {{{
+ * val myVec = VecInit(5.U, 10.U, 13.U)
+ * printf(p"myVec = \$myVec\n")
+ * // myVec = Vec(5, 10, 13)
+ *
+ * val myBundle = Wire(new Bundle {
+ * val foo = UInt()
+ * val bar = UInt()
+ * })
+ * myBundle.foo := 3.U
+ * myBundle.bar := 11.U
+ * printf(p"myBundle = \$myBundle\n")
+ * // myBundle = Bundle(a -> 3, b -> 11)
+ * }}}
+ * Users can override the default behavior of `.toPrintable` in custom [[Bundle]] and [[Record]]
+ * types.
+ */
+// TODO Add support for names of Modules
+// Currently impossible because unpack is called before the name is selected
+// Could be implemented by adding a new format specifier to Firrtl (eg. %m)
+// TODO Should we provide more functions like map and mkPrintable?
+sealed abstract class Printable {
+ /** Unpack into format String and a List of String arguments (identifiers)
+ * @note This must be called after elaboration when Chisel nodes actually
+ * have names
+ */
+ def unpack(ctx: Component): (String, Iterable[String])
+ /** Allow for appending Printables like Strings */
+ final def +(that: Printable): Printables = Printables(List(this, that))
+ /** Allow for appending Strings to Printables */
+ final def +(that: String): Printables = Printables(List(this, PString(that)))
+}
+object Printable {
+ /** Pack standard printf fmt, args* style into Printable
+ */
+ def pack(fmt: String, data: Data*): Printable = { // scalastyle:ignore method.length
+ val args = data.toIterator
+
+ // Error handling
+ def carrotAt(index: Int) = (" " * index) + "^"
+ def errorMsg(index: Int) =
+ s"""| fmt = "$fmt"
+ | ${carrotAt(index)}
+ | data = ${data mkString ", "}""".stripMargin
+ def getArg(i: Int): Data = {
+ if (!args.hasNext) {
+ val msg = "has no matching argument!\n" + errorMsg(i)
+ // Exception wraps msg in s"Format Specifier '$msg'"
+ throw new MissingFormatArgumentException(msg)
+ }
+ args.next()
+ }
+
+ val pables = mutable.ListBuffer.empty[Printable]
+ var str = ""
+ var percent = false
+ for ((c, i) <- fmt.zipWithIndex) {
+ if (percent) {
+ val arg = c match {
+ case FirrtlFormat(x) => FirrtlFormat(x.toString, getArg(i))
+ case 'n' => Name(getArg(i))
+ case 'N' => FullName(getArg(i))
+ case '%' => Percent
+ case x =>
+ val msg = s"Illegal format specifier '$x'!\n" + errorMsg(i)
+ throw new UnknownFormatConversionException(msg)
+ }
+ pables += PString(str dropRight 1) // remove format %
+ pables += arg
+ str = ""
+ percent = false
+ } else {
+ str += c
+ percent = c == '%'
+ }
+ }
+ if (percent) {
+ val msg = s"Trailing %\n" + errorMsg(fmt.size - 1)
+ throw new UnknownFormatConversionException(msg)
+ }
+ require(!args.hasNext,
+ s"Too many arguments! More format specifier(s) expected!\n" +
+ errorMsg(fmt.size))
+
+ pables += PString(str)
+ Printables(pables)
+ }
+}
+
+case class Printables(pables: Iterable[Printable]) extends Printable {
+ require(pables.hasDefiniteSize, "Infinite-sized iterables are not supported!")
+ final def unpack(ctx: Component): (String, Iterable[String]) = {
+ val (fmts, args) = pables.map(_ unpack ctx).unzip
+ (fmts.mkString, args.flatten)
+ }
+}
+/** Wrapper for printing Scala Strings */
+case class PString(str: String) extends Printable {
+ final def unpack(ctx: Component): (String, Iterable[String]) =
+ (str replaceAll ("%", "%%"), List.empty)
+}
+/** Superclass for Firrtl format specifiers for Bits */
+sealed abstract class FirrtlFormat(private[chisel3] val specifier: Char) extends Printable {
+ def bits: Bits
+ def unpack(ctx: Component): (String, Iterable[String]) = {
+ (s"%$specifier", List(bits.ref.fullName(ctx)))
+ }
+}
+object FirrtlFormat {
+ final val legalSpecifiers = List('d', 'x', 'b', 'c')
+
+ def unapply(x: Char): Option[Char] =
+ Option(x) filter (x => legalSpecifiers contains x)
+
+ /** Helper for constructing Firrtl Formats
+ * Accepts data to simplify pack
+ */
+ def apply(specifier: String, data: Data): FirrtlFormat = {
+ val bits = data match {
+ case b: Bits => b
+ case d => throw new Exception(s"Trying to construct FirrtlFormat with non-bits $d!")
+ }
+ specifier match {
+ case "d" => Decimal(bits)
+ case "x" => Hexadecimal(bits)
+ case "b" => Binary(bits)
+ case "c" => Character(bits)
+ case c => throw new Exception(s"Illegal format specifier '$c'!")
+ }
+ }
+}
+/** Format bits as Decimal */
+case class Decimal(bits: Bits) extends FirrtlFormat('d')
+/** Format bits as Hexidecimal */
+case class Hexadecimal(bits: Bits) extends FirrtlFormat('x')
+/** Format bits as Binary */
+case class Binary(bits: Bits) extends FirrtlFormat('b')
+/** Format bits as Character */
+case class Character(bits: Bits) extends FirrtlFormat('c')
+/** Put innermost name (eg. field of bundle) */
+case class Name(data: Data) extends Printable {
+ final def unpack(ctx: Component): (String, Iterable[String]) = (data.ref.name, List.empty)
+}
+/** Put full name within parent namespace (eg. bundleName.field) */
+case class FullName(data: Data) extends Printable {
+ final def unpack(ctx: Component): (String, Iterable[String]) = (data.ref.fullName(ctx), List.empty)
+}
+/** Represents escaped percents */
+case object Percent extends Printable {
+ final def unpack(ctx: Component): (String, Iterable[String]) = ("%%", List.empty)
+}
diff --git a/core/src/main/scala/chisel3/Printf.scala b/core/src/main/scala/chisel3/Printf.scala
new file mode 100644
index 00000000..0478e889
--- /dev/null
+++ b/core/src/main/scala/chisel3/Printf.scala
@@ -0,0 +1,102 @@
+// See LICENSE for license details.
+
+package chisel3
+
+import scala.language.experimental.macros
+
+import chisel3.internal._
+import chisel3.internal.Builder.pushCommand
+import chisel3.internal.firrtl._
+import chisel3.internal.sourceinfo.SourceInfo
+
+/** Prints a message in simulation
+ *
+ * See apply methods for use
+ */
+object printf { // scalastyle:ignore object.name
+ /** Helper for packing escape characters */
+ private[chisel3] def format(formatIn: String): String = {
+ require(formatIn forall (c => c.toInt > 0 && c.toInt < 128),
+ "format strings must comprise non-null ASCII values")
+ def escaped(x: Char) = {
+ require(x.toInt >= 0, s"char ${x} to Int ${x.toInt} must be >= 0")
+ if (x == '"' || x == '\\') {
+ s"\\${x}"
+ } else if (x == '\n') {
+ "\\n"
+ } else if (x == '\t') {
+ "\\t"
+ } else {
+ require(x.toInt >= 32, s"char ${x} to Int ${x.toInt} must be >= 32") // TODO \xNN once FIRRTL issue #59 is resolved
+ x
+ }
+ }
+ formatIn map escaped mkString ""
+ }
+
+ /** Prints a message in simulation
+ *
+ * Prints a message every cycle. If defined within the scope of a [[when]] block, the message
+ * will only be printed on cycles that the when condition is true.
+ *
+ * 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), uses the current default clock
+ * and reset. These can be overriden with [[withClockAndReset]].
+ *
+ * ==Format Strings==
+ *
+ * This method expects a ''format string'' and an ''argument list'' in a similar style to printf
+ * in C. The format string expects a [[scala.Predef.String String]] that may contain ''format
+ * specifiers'' For example:
+ * {{{
+ * printf("myWire has the value %d\n", myWire)
+ * }}}
+ * This prints the string "myWire has the value " followed by the current value of `myWire` (in
+ * decimal, followed by a newline.
+ *
+ * There must be exactly as many arguments as there are format specifiers
+ *
+ * ===Format Specifiers===
+ *
+ * Format specifiers are prefixed by `%`. If you wish to print a literal `%`, use `%%`.
+ * - `%d` - Decimal
+ * - `%x` - Hexadecimal
+ * - `%b` - Binary
+ * - `%c` - 8-bit Character
+ * - `%n` - Name of a signal
+ * - `%N` - Full name of a leaf signal (in an aggregate)
+ *
+ * @param fmt printf format string
+ * @param data format string varargs containing data to print
+ */
+ def apply(fmt: String, data: Bits*)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Unit =
+ apply(Printable.pack(fmt, data:_*))
+ /** Prints a message in simulation
+ *
+ * Prints a message every cycle. If defined within the scope of a [[when]] block, the message
+ * will only be printed on cycles that the when condition is true.
+ *
+ * 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), uses the current default clock
+ * and reset. These can be overriden with [[withClockAndReset]].
+ *
+ * @see [[Printable]] documentation
+ * @param pable [[Printable]] to print
+ */
+ def apply(pable: Printable)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Unit = {
+ when (!Module.reset.asBool) {
+ printfWithoutReset(pable)
+ }
+ }
+
+ private[chisel3] def printfWithoutReset(pable: Printable)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Unit = { // scalastyle:ignore line.size.limit
+ val clock = Builder.forcedClock
+ pushCommand(Printf(sourceInfo, clock.ref, pable))
+ }
+ private[chisel3] def printfWithoutReset(fmt: String, data: Bits*)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Unit = // scalastyle:ignore line.size.limit
+ printfWithoutReset(Printable.pack(fmt, data:_*))
+}
diff --git a/core/src/main/scala/chisel3/RawModule.scala b/core/src/main/scala/chisel3/RawModule.scala
new file mode 100644
index 00000000..218022cc
--- /dev/null
+++ b/core/src/main/scala/chisel3/RawModule.scala
@@ -0,0 +1,233 @@
+// See LICENSE for license details.
+
+package chisel3
+
+import scala.collection.mutable.{ArrayBuffer, HashMap}
+import scala.collection.JavaConversions._
+import scala.language.experimental.macros
+
+import chisel3.experimental.BaseModule
+import chisel3.internal._
+import chisel3.internal.Builder._
+import chisel3.internal.firrtl._
+import chisel3.internal.sourceinfo.UnlocatableSourceInfo
+
+/** Abstract base class for Modules that contain Chisel RTL.
+ * This abstract base class is a user-defined module which does not include implicit clock and reset and supports
+ * multiple IO() declarations.
+ */
+abstract class RawModule(implicit moduleCompileOptions: CompileOptions)
+ extends BaseModule {
+ //
+ // RTL construction internals
+ //
+ private val _commands = ArrayBuffer[Command]()
+ private[chisel3] def addCommand(c: Command) {
+ require(!_closed, "Can't write to module after module close")
+ _commands += c
+ }
+ protected def getCommands = {
+ require(_closed, "Can't get commands before module close")
+ _commands.toSeq
+ }
+
+ //
+ // Other Internal Functions
+ //
+ // For debuggers/testers, TODO: refactor out into proper public API
+ private var _firrtlPorts: Option[Seq[firrtl.Port]] = None
+ lazy val getPorts = _firrtlPorts.get
+
+ val compileOptions = moduleCompileOptions
+
+ private[chisel3] def namePorts(names: HashMap[HasId, String]): Unit = {
+ for (port <- getModulePorts) {
+ port.suggestedName.orElse(names.get(port)) match {
+ case Some(name) =>
+ if (_namespace.contains(name)) {
+ Builder.error(s"""Unable to name port $port to "$name" in $this,""" +
+ " name is already taken by another port!")
+ }
+ port.setRef(ModuleIO(this, _namespace.name(name)))
+ case None =>
+ Builder.error(s"Unable to name port $port in $this, " +
+ "try making it a public field of the Module")
+ port.setRef(ModuleIO(this, "<UNNAMED>"))
+ }
+ }
+ }
+
+
+ private[chisel3] override def generateComponent(): Component = { // scalastyle:ignore cyclomatic.complexity
+ require(!_closed, "Can't generate module more than once")
+ _closed = true
+
+ val names = nameIds(classOf[RawModule])
+
+ // Ports get first naming priority, since they are part of a Module's IO spec
+ namePorts(names)
+
+ // Then everything else gets named
+ for ((node, name) <- names) {
+ node.suggestName(name)
+ }
+
+ // All suggestions are in, force names to every node.
+ for (id <- getIds) {
+ id match {
+ case id: BaseModule => id.forceName(default=id.desiredName, _namespace)
+ case id: MemBase[_] => id.forceName(default="_T", _namespace)
+ case id: Data =>
+ if (id.isSynthesizable) {
+ id.topBinding match {
+ case OpBinding(_) | MemoryPortBinding(_) | PortBinding(_) | RegBinding(_) | WireBinding(_) =>
+ id.forceName(default="_T", _namespace)
+ case _ => // don't name literals
+ }
+ } // else, don't name unbound types
+ }
+ id._onModuleClose
+ }
+
+ val firrtlPorts = getModulePorts map { port: Data =>
+ // Special case Vec to make FIRRTL emit the direction of its
+ // element.
+ // Just taking the Vec's specifiedDirection is a bug in cases like
+ // Vec(Flipped()), since the Vec's specifiedDirection is
+ // Unspecified.
+ val direction = port match {
+ case v: Vec[_] => v.specifiedDirection match {
+ case SpecifiedDirection.Input => SpecifiedDirection.Input
+ case SpecifiedDirection.Output => SpecifiedDirection.Output
+ case SpecifiedDirection.Flip => SpecifiedDirection.flip(v.sample_element.specifiedDirection)
+ case SpecifiedDirection.Unspecified => v.sample_element.specifiedDirection
+ }
+ case _ => port.specifiedDirection
+ }
+
+ Port(port, direction)
+ }
+ _firrtlPorts = Some(firrtlPorts)
+
+ // Generate IO invalidation commands to initialize outputs as unused,
+ // unless the client wants explicit control over their generation.
+ val invalidateCommands = {
+ if (!compileOptions.explicitInvalidate) {
+ getModulePorts map { port => DefInvalid(UnlocatableSourceInfo, port.ref) }
+ } else {
+ Seq()
+ }
+ }
+ val component = DefModule(this, name, firrtlPorts, invalidateCommands ++ getCommands)
+ _component = Some(component)
+ component
+ }
+
+ private[chisel3] def initializeInParent(parentCompileOptions: CompileOptions): Unit = {
+ implicit val sourceInfo = UnlocatableSourceInfo
+
+ if (!parentCompileOptions.explicitInvalidate) {
+ for (port <- getModulePorts) {
+ pushCommand(DefInvalid(sourceInfo, port.ref))
+ }
+ }
+ }
+}
+
+trait RequireAsyncReset extends MultiIOModule {
+ override private[chisel3] def mkReset: AsyncReset = AsyncReset()
+}
+
+trait RequireSyncReset extends MultiIOModule {
+ override private[chisel3] def mkReset: Bool = Bool()
+}
+
+/** 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).
+ * This abstract base class includes an implicit clock and reset.
+ *
+ * @note Module instantiations must be wrapped in a Module() call.
+ */
+abstract class MultiIOModule(implicit moduleCompileOptions: CompileOptions)
+ extends RawModule {
+ // Implicit clock and reset pins
+ final val clock: Clock = IO(Input(Clock()))
+ final val reset: Reset = IO(Input(mkReset))
+
+ private[chisel3] def mkReset: Reset = {
+ // Top module and compatibility mode use Bool for reset
+ val inferReset = _parent.isDefined && moduleCompileOptions.inferModuleReset
+ if (inferReset) Reset() else Bool()
+ }
+
+ // Setup ClockAndReset
+ Builder.currentClock = Some(clock)
+ Builder.currentReset = Some(reset)
+
+ private[chisel3] override def initializeInParent(parentCompileOptions: CompileOptions): Unit = {
+ implicit val sourceInfo = UnlocatableSourceInfo
+
+ super.initializeInParent(parentCompileOptions)
+ clock := Builder.forcedClock
+ reset := Builder.forcedReset
+ }
+}
+
+package internal {
+
+ /** Legacy Module class that restricts IOs to just io, clock, and reset, and provides a constructor
+ * for threading through explicit clock and reset.
+ *
+ * While this class isn't planned to be removed anytime soon (there are benefits to restricting
+ * IO), the clock and reset constructors will be phased out. Recommendation is to wrap the module
+ * in a withClock/withReset/withClockAndReset block, or directly hook up clock or reset IO pins.
+ */
+ abstract class LegacyModule(implicit moduleCompileOptions: CompileOptions)
+ extends MultiIOModule {
+ // These are to be phased out
+ protected var override_clock: Option[Clock] = None
+ protected var override_reset: Option[Bool] = None
+
+ // 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: Record
+
+ // Allow access to bindings from the compatibility package
+ protected def _compatIoPortBound() = portsContains(io)// scalastyle:ignore method.name
+
+ private[chisel3] override def namePorts(names: HashMap[HasId, String]): Unit = {
+ for (port <- getModulePorts) {
+ // This should already have been caught
+ if (!names.contains(port)) throwException(s"Unable to name port $port in $this")
+ val name = names(port)
+ port.setRef(ModuleIO(this, _namespace.name(name)))
+ }
+ }
+
+ private[chisel3] override def generateComponent(): Component = {
+ _compatAutoWrapPorts() // pre-IO(...) compatibility hack
+
+ // Restrict IO to just io, clock, and reset
+ require(io != null, "Module must have io")
+ require(portsContains(io), "Module must have io wrapped in IO(...)")
+ require((portsContains(clock)) && (portsContains(reset)), "Internal error, module did not have clock or reset as IO") // scalastyle:ignore line.size.limit
+ require(portsSize == 3, "Module must only have io, clock, and reset as IO")
+
+ super.generateComponent()
+ }
+
+ private[chisel3] override def initializeInParent(parentCompileOptions: CompileOptions): Unit = {
+ // Don't generate source info referencing parents inside a module, since this interferes with
+ // module de-duplication in FIRRTL emission.
+ implicit val sourceInfo = UnlocatableSourceInfo
+
+ if (!parentCompileOptions.explicitInvalidate) {
+ pushCommand(DefInvalid(sourceInfo, io.ref))
+ }
+
+ clock := override_clock.getOrElse(Builder.forcedClock)
+ reset := override_reset.getOrElse(Builder.forcedReset)
+ }
+ }
+}
diff --git a/core/src/main/scala/chisel3/Reg.scala b/core/src/main/scala/chisel3/Reg.scala
new file mode 100644
index 00000000..7129c389
--- /dev/null
+++ b/core/src/main/scala/chisel3/Reg.scala
@@ -0,0 +1,195 @@
+// See LICENSE for license details.
+
+package chisel3
+
+import scala.language.experimental.macros
+
+import chisel3.internal._
+import chisel3.internal.Builder.pushCommand
+import chisel3.internal.firrtl._
+import chisel3.internal.sourceinfo.SourceInfo
+
+/** Utility for constructing hardware registers
+ *
+ * The width of a `Reg` (inferred or not) is copied from the type template
+ * {{{
+ * val r0 = Reg(UInt()) // width is inferred
+ * val r1 = Reg(UInt(8.W)) // width is set to 8
+ *
+ * val r2 = Reg(Vec(4, UInt())) // width is inferred
+ * val r3 = Reg(Vec(4, UInt(8.W))) // width of each element is set to 8
+ *
+ * class MyBundle {
+ * val unknown = UInt()
+ * val known = UInt(8.W)
+ * }
+ * val r4 = Reg(new MyBundle)
+ * // Width of r4.unknown is inferred
+ * // Width of r4.known is set to 8
+ * }}}
+ *
+ */
+object Reg {
+ /** Construct a [[Reg]] from a type template with no initialization value (reset is ignored).
+ * Value will not change unless the [[Reg]] is given a connection.
+ * @param t The template from which to construct this wire
+ */
+ def apply[T <: Data](t: T)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): T = {
+ if (compileOptions.declaredTypeMustBeUnbound) {
+ requireIsChiselType(t, "reg type")
+ }
+ val reg = t.cloneTypeFull
+ val clock = Node(Builder.forcedClock)
+
+ reg.bind(RegBinding(Builder.forcedUserModule))
+ pushCommand(DefReg(sourceInfo, reg, clock))
+ reg
+ }
+
+}
+
+/** Utility for constructing one-cycle delayed versions of signals
+ *
+ * ''The width of a `RegNext` is not set based on the `next` or `init` connections'' for [[Element]] types. In the
+ * following example, the width of `bar` will not be set and will be inferred by the FIRRTL compiler.
+ * {{{
+ * val foo = Reg(UInt(4.W)) // width is 4
+ * val bar = RegNext(foo) // width is unset
+ * }}}
+ *
+ * If you desire an explicit width, do not use `RegNext` and instead use a register with a specified width:
+ * {{{
+ * val foo = Reg(UInt(4.W)) // width is 4
+ * val bar = Reg(chiselTypeOf(foo)) // width is 4
+ * bar := foo
+ * }}}
+ *
+ * Also note that a `RegNext` of a [[Bundle]] ''will have it's width set'' for [[Aggregate]] types.
+ * {{{
+ * class MyBundle extends Bundle {
+ * val x = UInt(4.W)
+ * }
+ * val foo = Wire(new MyBundle) // the width of foo.x is 4
+ * val bar = RegNext(foo) // the width of bar.x is 4
+ * }}}
+ */
+object RegNext {
+ /** Returns a register ''with an unset width'' connected to the signal `next` and with no reset value. */
+ def apply[T <: Data](next: T)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): T = {
+ val model = (next match {
+ case next: Bits => next.cloneTypeWidth(Width())
+ case next => next.cloneTypeFull
+ }).asInstanceOf[T]
+ val reg = Reg(model)
+
+ requireIsHardware(next, "reg next")
+ reg := next
+
+ reg
+ }
+
+ /** Returns a register ''with an unset width'' connected to the signal `next` and with the reset value `init`. */
+ def apply[T <: Data](next: T, init: T)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): T = {
+ val model = (next match {
+ case next: Bits => next.cloneTypeWidth(Width())
+ case next => next.cloneTypeFull
+ }).asInstanceOf[T]
+ val reg = RegInit(model, init) // TODO: this makes NO sense
+
+ requireIsHardware(next, "reg next")
+ reg := next
+
+ reg
+ }
+}
+
+/** Utility for constructing hardware registers with an initialization value.
+ *
+ * The register is set to the initialization value when the current implicit `reset` is high
+ *
+ * The two forms of `RegInit` differ in how the type and width of the resulting [[Reg]] are
+ * specified.
+ *
+ * ==Single Argument==
+ * The single argument form uses the argument to specify both the type and reset value. For
+ * non-literal [[Bits]], the width of the [[Reg]] will be inferred. For literal [[Bits]] and all
+ * non-Bits arguments, the type will be copied from the argument. See the following examples for
+ * more details:
+ *
+ * 1. Literal [[Bits]] initializer: width will be set to match
+ * {{{
+ * val r1 = RegInit(1.U) // width will be inferred to be 1
+ * val r2 = RegInit(1.U(8.W)) // width is set to 8
+ * }}}
+ *
+ * 2. Non-Literal [[Element]] initializer - width will be inferred
+ * {{{
+ * val x = Wire(UInt())
+ * val y = Wire(UInt(8.W))
+ * val r1 = RegInit(x) // width will be inferred
+ * val r2 = RegInit(y) // width is set to 8
+ * }}}
+ *
+ * 3. [[Aggregate]] initializer - width will be set to match the aggregate
+ *
+ * {{{
+ * class MyBundle extends Bundle {
+ * val unknown = UInt()
+ * val known = UInt(8.W)
+ * }
+ * val w1 = Reg(new MyBundle)
+ * val w2 = RegInit(w1)
+ * // Width of w2.unknown is inferred
+ * // Width of w2.known is set to 8
+ * }}}
+ *
+ * ==Double Argument==
+ * The double argument form allows the type of the [[Reg]] and the default connection to be
+ * specified independently.
+ *
+ * The width inference semantics for `RegInit` with two arguments match those of [[Reg]]. The
+ * first argument to `RegInit` is the type template which defines the width of the `Reg` in
+ * exactly the same way as the only argument to [[Wire]].
+ *
+ * More explicitly, you can reason about `RegInit` with multiple arguments as if it were defined
+ * as:
+ * {{{
+ * def RegInit[T <: Data](t: T, init: T): T = {
+ * val x = Reg(t)
+ * x := init
+ * x
+ * }
+ * }}}
+ */
+object RegInit {
+ /** Construct a [[Reg]] from a type template initialized to the specified value on reset
+ * @param t The type template used to construct this [[Reg]]
+ * @param init The value the [[Reg]] is initialized to on reset
+ */
+ def apply[T <: Data](t: T, init: T)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): T = {
+ if (compileOptions.declaredTypeMustBeUnbound) {
+ requireIsChiselType(t, "reg type")
+ }
+ val reg = t.cloneTypeFull
+ val clock = Builder.forcedClock
+ val reset = Builder.forcedReset
+
+ reg.bind(RegBinding(Builder.forcedUserModule))
+ requireIsHardware(init, "reg initializer")
+ pushCommand(DefRegInit(sourceInfo, reg, clock.ref, reset.ref, init.ref))
+ reg
+ }
+
+ /** Construct a [[Reg]] initialized on reset to the specified value.
+ * @param init Initial value that serves as a type template and reset value
+ */
+ def apply[T <: Data](init: T)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): T = {
+ val model = (init match {
+ // If init is a literal without forced width OR any non-literal, let width be inferred
+ case init: Bits if !init.litIsForcedWidth.getOrElse(false) => init.cloneTypeWidth(Width())
+ case init => init.cloneTypeFull
+ }).asInstanceOf[T]
+ RegInit(model, init)
+ }
+
+}
diff --git a/core/src/main/scala/chisel3/SIntFactory.scala b/core/src/main/scala/chisel3/SIntFactory.scala
new file mode 100644
index 00000000..c1c6b1db
--- /dev/null
+++ b/core/src/main/scala/chisel3/SIntFactory.scala
@@ -0,0 +1,25 @@
+// See LICENSE for license details.
+
+package chisel3
+
+import chisel3.internal.firrtl.{IntervalRange, SLit, Width}
+
+trait SIntFactory {
+ /** Create an SInt type with inferred width. */
+ def apply(): SInt = apply(Width())
+ /** Create a SInt type or port with fixed width. */
+ def apply(width: Width): SInt = new SInt(width)
+
+ /** Create a SInt with the specified range */
+ def apply(range: IntervalRange): SInt = {
+ apply(range.getWidth)
+ }
+
+ /** Create an SInt literal with specified width. */
+ // scalastyle:off method.name
+ protected[chisel3] def Lit(value: BigInt, width: Width): SInt = {
+ val lit = SLit(value, width)
+ val result = new SInt(lit.width)
+ lit.bindLitArg(result)
+ }
+}
diff --git a/core/src/main/scala/chisel3/SeqUtils.scala b/core/src/main/scala/chisel3/SeqUtils.scala
new file mode 100644
index 00000000..28f753b1
--- /dev/null
+++ b/core/src/main/scala/chisel3/SeqUtils.scala
@@ -0,0 +1,128 @@
+// See LICENSE for license details.
+
+package chisel3
+
+import chisel3.experimental.FixedPoint
+import chisel3.internal.throwException
+
+import scala.language.experimental.macros
+import chisel3.internal.sourceinfo._
+
+//scalastyle:off method.name
+
+private[chisel3] object SeqUtils {
+ /** Concatenates the data elements of the input sequence, in sequence order, together.
+ * The first element of the sequence forms the least significant bits, while the last element
+ * in the sequence forms the most significant bits.
+ *
+ * Equivalent to r(n-1) ## ... ## r(1) ## r(0).
+ */
+ def asUInt[T <: Bits](in: Seq[T]): UInt = macro SourceInfoTransform.inArg
+
+ /** @group SourceInfoTransformMacros */
+ def do_asUInt[T <: Bits](in: Seq[T])(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): 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
+ }
+ }
+
+ /** Outputs the number of elements that === true.B.
+ */
+ def count(in: Seq[Bool]): UInt = macro SourceInfoTransform.inArg
+
+ /** @group SourceInfoTransformMacros */
+ def do_count(in: Seq[Bool])(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): UInt = in.size match {
+ case 0 => 0.U
+ case 1 => in.head
+ case n =>
+ val sum = count(in take n/2) +& count(in drop n/2)
+ sum(BigInt(n).bitLength - 1, 0)
+ }
+
+ /** Returns the data value corresponding to the first true predicate.
+ */
+ def priorityMux[T <: Data](in: Seq[(Bool, T)]): T = macro SourceInfoTransform.inArg
+
+ /** @group SourceInfoTransformMacros */
+ def do_priorityMux[T <: Data](in: Seq[(Bool, T)])
+ (implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): T = {
+ if (in.size == 1) {
+ in.head._2
+ } else {
+ Mux(in.head._1, in.head._2, priorityMux(in.tail))
+ }
+ }
+
+ /** Returns the data value corresponding to the lone true predicate.
+ * This is elaborated to firrtl using a structure that should be optimized into and and/or tree.
+ *
+ * @note assumes exactly one true predicate, results undefined otherwise
+ * FixedPoint values or aggregates containing FixedPoint values cause this optimized structure to be lost
+ */
+ def oneHotMux[T <: Data](in: Iterable[(Bool, T)]): T = macro SourceInfoTransform.inArg
+
+ //scalastyle:off method.length cyclomatic.complexity
+ /** @group SourceInfoTransformMacros */
+ def do_oneHotMux[T <: Data](in: Iterable[(Bool, T)])
+ (implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): T = {
+ if (in.tail.isEmpty) {
+ in.head._2
+ }
+ else {
+ val output = cloneSupertype(in.toSeq map { _._2}, "oneHotMux")
+
+ def buildAndOrMultiplexor[TT <: Data](inputs: Iterable[(Bool, TT)]): T = {
+ val masked = for ((s, i) <- inputs) yield Mux(s, i.asUInt(), 0.U)
+ masked.reduceLeft(_ | _).asTypeOf(output)
+ }
+
+ output match {
+ case _: SInt =>
+ // SInt's have to be managed carefully so sign extension works
+
+ val sInts: Iterable[(Bool, SInt)] = in.collect { case (s: Bool, f: SInt) =>
+ (s, f.asTypeOf(output).asInstanceOf[SInt])
+ }
+
+ val masked = for ((s, i) <- sInts) yield Mux(s, i, 0.S)
+ masked.reduceLeft(_ | _).asTypeOf(output)
+
+ case _: FixedPoint =>
+ val (sels, possibleOuts) = in.toSeq.unzip
+
+ val (intWidths, binaryPoints) = in.toSeq.map { case (_, o) =>
+ val fo = o.asInstanceOf[FixedPoint]
+ require(fo.binaryPoint.known, "Mux1H requires width/binary points to be defined")
+ (fo.getWidth - fo.binaryPoint.get, fo.binaryPoint.get)
+ }.unzip
+
+ if (intWidths.distinct.length == 1 && binaryPoints.distinct.length == 1) {
+ buildAndOrMultiplexor(in)
+ }
+ else {
+ val maxIntWidth = intWidths.max
+ val maxBP = binaryPoints.max
+ val inWidthMatched = Seq.fill(intWidths.length)(Wire(FixedPoint((maxIntWidth + maxBP).W, maxBP.BP)))
+ inWidthMatched.zipWithIndex foreach { case (e, idx) => e := possibleOuts(idx).asInstanceOf[FixedPoint] }
+ buildAndOrMultiplexor(sels.zip(inWidthMatched))
+ }
+
+ case _: Aggregate =>
+ val allDefineWidth = in.forall { case (_, element) => element.widthOption.isDefined }
+ if(allDefineWidth) {
+ buildAndOrMultiplexor(in)
+ }
+ else {
+ throwException(s"Cannot Mux1H with aggregates with inferred widths")
+ }
+
+ case _ =>
+ buildAndOrMultiplexor(in)
+ }
+ }
+ }
+}
diff --git a/core/src/main/scala/chisel3/StrongEnum.scala b/core/src/main/scala/chisel3/StrongEnum.scala
new file mode 100644
index 00000000..8edce4d8
--- /dev/null
+++ b/core/src/main/scala/chisel3/StrongEnum.scala
@@ -0,0 +1,343 @@
+// See LICENSE for license details.
+
+package chisel3.experimental
+
+import scala.language.experimental.macros
+import scala.reflect.macros.blackbox.Context
+import scala.collection.mutable
+import chisel3._
+import chisel3.internal.Builder.pushOp
+import chisel3.internal.firrtl.PrimOp._
+import chisel3.internal.firrtl._
+import chisel3.internal.sourceinfo._
+import chisel3.internal.{Binding, Builder, ChildBinding, ConstrainedBinding, InstanceId, throwException}
+import firrtl.annotations._
+
+
+object EnumAnnotations {
+ /** An annotation for strong enum instances that are ''not'' inside of Vecs
+ *
+ * @param target the enum instance being annotated
+ * @param typeName the name of the enum's type (e.g. ''"mypackage.MyEnum"'')
+ */
+ case class EnumComponentAnnotation(target: Named, enumTypeName: String) extends SingleTargetAnnotation[Named] {
+ def duplicate(n: Named): EnumComponentAnnotation = this.copy(target = n)
+ }
+
+ case class EnumComponentChiselAnnotation(target: InstanceId, enumTypeName: String) extends ChiselAnnotation {
+ def toFirrtl: EnumComponentAnnotation = EnumComponentAnnotation(target.toNamed, enumTypeName)
+ }
+
+ /** An annotation for Vecs of strong enums.
+ *
+ * The ''fields'' parameter deserves special attention, since it may be difficult to understand. Suppose you create a the following Vec:
+
+ * {{{
+ * VecInit(new Bundle {
+ * val e = MyEnum()
+ * val b = new Bundle {
+ * val inner_e = MyEnum()
+ * }
+ * val v = Vec(3, MyEnum())
+ * }
+ * }}}
+ *
+ * Then, the ''fields'' parameter will be: ''Seq(Seq("e"), Seq("b", "inner_e"), Seq("v"))''. Note that for any Vec that doesn't contain Bundles, this field will simply be an empty Seq.
+ *
+ * @param target the Vec being annotated
+ * @param typeName the name of the enum's type (e.g. ''"mypackage.MyEnum"'')
+ * @param fields a list of all chains of elements leading from the Vec instance to its inner enum fields.
+ *
+ */
+ case class EnumVecAnnotation(target: Named, typeName: String, fields: Seq[Seq[String]]) extends SingleTargetAnnotation[Named] {
+ def duplicate(n: Named) = this.copy(target = n)
+ }
+
+ case class EnumVecChiselAnnotation(target: InstanceId, typeName: String, fields: Seq[Seq[String]]) extends ChiselAnnotation {
+ override def toFirrtl = EnumVecAnnotation(target.toNamed, typeName, fields)
+ }
+
+ /** An annotation for enum types (rather than enum ''instances'').
+ *
+ * @param typeName the name of the enum's type (e.g. ''"mypackage.MyEnum"'')
+ * @param definition a map describing which integer values correspond to which enum names
+ */
+ case class EnumDefAnnotation(typeName: String, definition: Map[String, BigInt]) extends NoTargetAnnotation
+
+ case class EnumDefChiselAnnotation(typeName: String, definition: Map[String, BigInt]) extends ChiselAnnotation {
+ override def toFirrtl: Annotation = EnumDefAnnotation(typeName, definition)
+ }
+}
+import EnumAnnotations._
+
+
+abstract class EnumType(private val factory: EnumFactory, selfAnnotating: Boolean = true) extends Element {
+ override def toString: String = {
+ val bindingString = litOption match {
+ case Some(value) => factory.nameOfValue(value) match {
+ case Some(name) => s"($value=$name)"
+ case None => s"($value=(invalid))"
+ }
+ case _ => bindingToString
+ }
+ // Use getSimpleName instead of enumTypeName because for debugging purposes the fully qualified name isn't
+ // necessary (compared to for the Enum annotation), and it's more consistent with Bundle printing.
+ s"${factory.getClass.getSimpleName.init}$bindingString"
+ }
+
+ override def cloneType: this.type = factory().asInstanceOf[this.type]
+
+ private[chisel3] def compop(sourceInfo: SourceInfo, op: PrimOp, other: EnumType): Bool = {
+ requireIsHardware(this, "bits operated on")
+ requireIsHardware(other, "bits operated on")
+
+ if(!this.typeEquivalent(other)) {
+ throwException(s"Enum types are not equivalent: ${this.enumTypeName}, ${other.enumTypeName}")
+ }
+
+ pushOp(DefPrim(sourceInfo, Bool(), op, this.ref, other.ref))
+ }
+
+ private[chisel3] override def typeEquivalent(that: Data): Boolean = {
+ this.getClass == that.getClass &&
+ this.factory == that.asInstanceOf[EnumType].factory
+ }
+
+ private[chisel3] override def connectFromBits(that: Bits)(implicit sourceInfo: SourceInfo,
+ compileOptions: CompileOptions): Unit = {
+ this := factory.apply(that.asUInt)
+ }
+
+ final def === (that: EnumType): Bool = macro SourceInfoTransform.thatArg
+ final def =/= (that: EnumType): Bool = macro SourceInfoTransform.thatArg
+ final def < (that: EnumType): Bool = macro SourceInfoTransform.thatArg
+ final def <= (that: EnumType): Bool = macro SourceInfoTransform.thatArg
+ final def > (that: EnumType): Bool = macro SourceInfoTransform.thatArg
+ final def >= (that: EnumType): Bool = macro SourceInfoTransform.thatArg
+
+ // scalastyle:off line.size.limit method.name
+ def do_=== (that: EnumType)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Bool = compop(sourceInfo, EqualOp, that)
+ def do_=/= (that: EnumType)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Bool = compop(sourceInfo, NotEqualOp, that)
+ def do_< (that: EnumType)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Bool = compop(sourceInfo, LessOp, that)
+ def do_> (that: EnumType)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Bool = compop(sourceInfo, GreaterOp, that)
+ def do_<= (that: EnumType)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Bool = compop(sourceInfo, LessEqOp, that)
+ def do_>= (that: EnumType)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Bool = compop(sourceInfo, GreaterEqOp, that)
+ // scalastyle:on line.size.limit method.name
+
+ override def do_asUInt(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): UInt =
+ pushOp(DefPrim(sourceInfo, UInt(width), AsUIntOp, ref))
+
+ protected[chisel3] override def width: Width = factory.width
+
+ def isValid(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Bool = {
+ if (litOption.isDefined) {
+ true.B
+ } else {
+ factory.all.map(this === _).reduce(_ || _)
+ }
+ }
+
+ def next(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): this.type = {
+ if (litOption.isDefined) {
+ val index = factory.all.indexOf(this)
+
+ if (index < factory.all.length-1) {
+ factory.all(index + 1).asInstanceOf[this.type]
+ } else {
+ factory.all.head.asInstanceOf[this.type]
+ }
+ } else {
+ val enums_with_nexts = factory.all zip (factory.all.tail :+ factory.all.head)
+ val next_enum = SeqUtils.priorityMux(enums_with_nexts.map { case (e,n) => (this === e, n) } )
+ next_enum.asInstanceOf[this.type]
+ }
+ }
+
+ private[chisel3] def bindToLiteral(num: BigInt, w: Width): Unit = {
+ val lit = ULit(num, w)
+ lit.bindLitArg(this)
+ }
+
+ override private[chisel3] def bind(target: Binding, parentDirection: SpecifiedDirection = SpecifiedDirection.Unspecified): Unit = {
+ super.bind(target, parentDirection)
+
+ // Make sure we only annotate hardware and not literals
+ if (selfAnnotating && isSynthesizable && topBindingOpt.get.isInstanceOf[ConstrainedBinding]) {
+ annotateEnum()
+ }
+ }
+
+ // This function conducts a depth-wise search to find all enum-type fields within a vector or bundle (or vector of bundles)
+ private def enumFields(d: Aggregate): Seq[Seq[String]] = d match {
+ case v: Vec[_] => v.sample_element match {
+ case b: Bundle => enumFields (b)
+ case _ => Seq ()
+ }
+ case b: Bundle =>
+ b.elements.collect {
+ case (name, e: EnumType) if this.typeEquivalent(e) => Seq(Seq(name))
+ case (name, v: Vec[_]) if this.typeEquivalent(v.sample_element) => Seq(Seq(name))
+ case (name, b2: Bundle) => enumFields(b2).map(name +: _)
+ }.flatten.toSeq
+ }
+
+ private def outerMostVec(d: Data = this): Option[Vec[_]] = {
+ val currentVecOpt = d match {
+ case v: Vec[_] => Some(v)
+ case _ => None
+ }
+
+ d.binding match {
+ case Some(ChildBinding(parent)) => outerMostVec(parent) match {
+ case outer @ Some(_) => outer
+ case None => currentVecOpt
+ }
+ case _ => currentVecOpt
+ }
+ }
+
+ private def annotateEnum(): Unit = {
+ val anno = outerMostVec() match {
+ case Some(v) => EnumVecChiselAnnotation(v, enumTypeName, enumFields(v))
+ case None => EnumComponentChiselAnnotation(this, enumTypeName)
+ }
+
+ if (!Builder.annotations.contains(anno)) {
+ annotate(anno)
+ }
+
+ if (!Builder.annotations.contains(factory.globalAnnotation)) {
+ annotate(factory.globalAnnotation)
+ }
+ }
+
+ protected def enumTypeName: String = factory.enumTypeName
+
+ def toPrintable: Printable = FullName(this) // TODO: Find a better pretty printer
+}
+
+
+abstract class EnumFactory {
+ class Type extends EnumType(this)
+ object Type {
+ def apply(): Type = EnumFactory.this.apply()
+ }
+
+ private var id: BigInt = 0
+ private[chisel3] var width: Width = 0.W
+
+ private case class EnumRecord(inst: Type, name: String)
+ private val enum_records = mutable.ArrayBuffer.empty[EnumRecord]
+
+ private def enumNames = enum_records.map(_.name).toSeq
+ private def enumValues = enum_records.map(_.inst.litValue()).toSeq
+ private def enumInstances = enum_records.map(_.inst).toSeq
+
+ private[chisel3] val enumTypeName = getClass.getName.init
+
+ private[chisel3] def globalAnnotation: EnumDefChiselAnnotation =
+ EnumDefChiselAnnotation(enumTypeName, (enumNames, enumValues).zipped.toMap)
+
+ def getWidth: Int = width.get
+
+ def all: Seq[Type] = enumInstances
+
+ private[chisel3] def nameOfValue(id: BigInt): Option[String] = {
+ enum_records.find(_.inst.litValue() == id).map(_.name)
+ }
+
+ protected def Value: Type = macro EnumMacros.ValImpl // scalastyle:off method.name
+ protected def Value(id: UInt): Type = macro EnumMacros.ValCustomImpl // scalastyle:off method.name
+
+ protected def do_Value(name: String): Type = {
+ val result = new Type
+
+ // We have to use UnknownWidth here, because we don't actually know what the final width will be
+ result.bindToLiteral(id, UnknownWidth())
+
+ enum_records.append(EnumRecord(result, name))
+
+ width = (1 max id.bitLength).W
+ id += 1
+
+ result
+ }
+
+ protected def do_Value(name: String, id: UInt): Type = {
+ // TODO: These throw ExceptionInInitializerError which can be confusing to the user. Get rid of the error, and just
+ // throw an exception
+ if (id.litOption.isEmpty) {
+ throwException(s"$enumTypeName defined with a non-literal type")
+ }
+ if (id.litValue() < this.id) {
+ throwException(s"Enums must be strictly increasing: $enumTypeName")
+ }
+
+ this.id = id.litValue()
+ do_Value(name)
+ }
+
+ def apply(): Type = new Type
+
+ def apply(n: UInt)(implicit sourceInfo: SourceInfo, connectionCompileOptions: CompileOptions): Type = {
+ // scalastyle:off line.size.limit
+ if (n.litOption.isDefined) {
+ enumInstances.find(_.litValue == n.litValue) match {
+ case Some(result) => result
+ case None => throwException(s"${n.litValue} is not a valid value for $enumTypeName")
+ }
+ } else if (!n.isWidthKnown) {
+ throwException(s"Non-literal UInts being cast to $enumTypeName must have a defined width")
+ } else if (n.getWidth > this.getWidth) {
+ throwException(s"The UInt being cast to $enumTypeName is wider than $enumTypeName's width ($getWidth)")
+ } else {
+ Builder.warning(s"Casting non-literal UInt to $enumTypeName. You can check that its value is legal by calling isValid")
+
+ val glue = Wire(new UnsafeEnum(width))
+ glue := n
+ val result = Wire(new Type)
+ result := glue
+ result
+ }
+ }
+ // scalastyle:on line.size.limit
+}
+
+
+private[chisel3] object EnumMacros {
+ def ValImpl(c: Context) : c.Tree = { // scalastyle:off method.name
+ import c.universe._
+
+ // Much thanks to michael_s for this solution:
+ // stackoverflow.com/questions/18450203/retrieve-the-name-of-the-value-a-scala-macro-invocation-will-be-assigned-to
+ val term = c.internal.enclosingOwner
+ val name = term.name.decodedName.toString.trim
+
+ if (name.contains(" ")) {
+ c.abort(c.enclosingPosition, "Value cannot be called without assigning to an enum")
+ }
+
+ q"""this.do_Value($name)"""
+ }
+
+ def ValCustomImpl(c: Context)(id: c.Expr[UInt]): c.universe.Tree = { // scalastyle:off method.name
+ import c.universe._
+
+ val term = c.internal.enclosingOwner
+ val name = term.name.decodedName.toString.trim
+
+ if (name.contains(" ")) {
+ c.abort(c.enclosingPosition, "Value cannot be called without assigning to an enum")
+ }
+
+ q"""this.do_Value($name, $id)"""
+ }
+}
+
+
+// This is an enum type that can be connected directly to UInts. It is used as a "glue" to cast non-literal UInts
+// to enums.
+private[chisel3] class UnsafeEnum(override val width: Width) extends EnumType(UnsafeEnum, selfAnnotating = false) {
+ override def cloneType: this.type = new UnsafeEnum(width).asInstanceOf[this.type]
+}
+private object UnsafeEnum extends EnumFactory
diff --git a/core/src/main/scala/chisel3/UIntFactory.scala b/core/src/main/scala/chisel3/UIntFactory.scala
new file mode 100644
index 00000000..3868962b
--- /dev/null
+++ b/core/src/main/scala/chisel3/UIntFactory.scala
@@ -0,0 +1,47 @@
+// See LICENSE for license details.
+
+package chisel3
+
+import chisel3.internal.firrtl.{IntervalRange, KnownWidth, ULit, UnknownWidth, Width}
+import firrtl.Utils
+import firrtl.constraint.IsKnown
+import firrtl.ir.{Closed, IntWidth, Open}
+
+// This is currently a factory because both Bits and UInt inherit it.
+trait UIntFactory {
+ /** Create a UInt type with inferred width. */
+ def apply(): UInt = apply(Width())
+ /** Create a UInt port with specified width. */
+ def apply(width: Width): UInt = new UInt(width)
+
+ /** Create a UInt literal with specified width. */
+ // scalastyle:off method.name
+ protected[chisel3] def Lit(value: BigInt, width: Width): UInt = {
+ val lit = ULit(value, width)
+ val result = new UInt(lit.width)
+ // Bind result to being an Literal
+ lit.bindLitArg(result)
+ }
+ /** Create a UInt with the specified range, validate that range is effectively > 0
+ */
+ //scalastyle:off cyclomatic.complexity
+ def apply(range: IntervalRange): UInt = {
+ // Check is only done against lower bound because range will already insist that range high >= low
+ range.lowerBound match {
+ case Closed(bound) if bound < 0 =>
+ throw new ChiselException(s"Attempt to create UInt with closed lower bound of $bound, must be > 0")
+ case Open(bound) if bound < -1 =>
+ throw new ChiselException(s"Attempt to create UInt with open lower bound of $bound, must be > -1")
+ case _ =>
+ }
+
+ // because this is a UInt we don't have to take into account the lower bound
+ val newWidth = if(range.upperBound.isInstanceOf[IsKnown]) {
+ KnownWidth(Utils.getUIntWidth(range.maxAdjusted.get).max(1)) // max(1) handles range"[0,0]"
+ } else {
+ UnknownWidth()
+ }
+
+ apply(newWidth)
+ }
+}
diff --git a/core/src/main/scala/chisel3/When.scala b/core/src/main/scala/chisel3/When.scala
new file mode 100644
index 00000000..ea243bbe
--- /dev/null
+++ b/core/src/main/scala/chisel3/When.scala
@@ -0,0 +1,85 @@
+// See LICENSE for license details.
+
+package chisel3
+
+import scala.language.experimental.macros
+
+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
+ * 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 === 3.U ) {
+ * // Some logic to run when myData equals 3.
+ * } .elsewhen ( myData === 1.U ) {
+ * // 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: => Any)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): WhenContext = { // scalastyle:ignore line.size.limit
+ new WhenContext(sourceInfo, Some(() => cond), block)
+ }
+}
+
+/** A WhenContext may represent a when, and elsewhen, or an
+ * otherwise. Since FIRRTL does not have an "elsif" statement,
+ * alternatives must be mapped to nested if-else statements inside
+ * the alternatives of the preceeding condition. In order to emit
+ * proper FIRRTL, it is necessary to keep track of the depth of
+ * nesting of the FIRRTL whens. Due to the "thin frontend" nature of
+ * Chisel3, it is not possible to know if a when or elsewhen has a
+ * succeeding elsewhen or otherwise; therefore, this information is
+ * added by preprocessing the command queue.
+ */
+final class WhenContext(sourceInfo: SourceInfo, cond: Option[() => Bool], block: => Any, firrtlDepth: Int = 0) {
+
+ /** This block of logic gets executed if above conditions have been
+ * false and this condition is true. The lazy argument pattern
+ * makes it possible to delay evaluation of cond, emitting the
+ * declaration and assignment of the Bool node of the predicate in
+ * the correct place.
+ */
+ def elsewhen (elseCond: => Bool)(block: => Any)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): WhenContext = { // scalastyle:ignore line.size.limit
+ new WhenContext(sourceInfo, Some(() => elseCond), block, firrtlDepth + 1)
+ }
+
+ /** This block of logic gets executed only if the above conditions
+ * were all false. No additional logic blocks may be appended past
+ * the `otherwise`. The lazy argument pattern makes it possible to
+ * delay evaluation of cond, emitting the declaration and
+ * assignment of the Bool node of the predicate in the correct
+ * place.
+ */
+ def otherwise(block: => Any)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Unit =
+ new WhenContext(sourceInfo, None, block, firrtlDepth + 1)
+
+ /*
+ *
+ */
+ if (firrtlDepth > 0) { pushCommand(AltBegin(sourceInfo)) }
+ cond.foreach( c => pushCommand(WhenBegin(sourceInfo, c().ref)) )
+ Builder.whenDepth += 1
+ try {
+ block
+ } catch {
+ case ret: scala.runtime.NonLocalReturnControl[_] =>
+ throwException("Cannot exit from a when() block with a \"return\"!" +
+ " Perhaps you meant to use Mux or a Wire as a return value?"
+ )
+ }
+ Builder.whenDepth -= 1
+ cond.foreach( c => pushCommand(WhenEnd(sourceInfo,firrtlDepth)) )
+ if (cond.isEmpty) { pushCommand(OtherwiseEnd(sourceInfo,firrtlDepth)) }
+}
diff --git a/core/src/main/scala/chisel3/aop/Aspect.scala b/core/src/main/scala/chisel3/aop/Aspect.scala
new file mode 100644
index 00000000..9f10a0dd
--- /dev/null
+++ b/core/src/main/scala/chisel3/aop/Aspect.scala
@@ -0,0 +1,40 @@
+// See LICENSE for license details.
+
+package chisel3.aop
+
+import chisel3.RawModule
+import firrtl.annotations.{Annotation, NoTargetAnnotation}
+import firrtl.options.Unserializable
+import firrtl.AnnotationSeq
+
+/** Represents an aspect of a Chisel module, by specifying
+ * what behavior should be done to instance, via the FIRRTL Annotation Mechanism
+ * @tparam T Type of top-level module
+ */
+abstract class Aspect[T <: RawModule] extends Annotation with Unserializable with NoTargetAnnotation {
+ /** Convert this Aspect to a seq of FIRRTL annotation
+ * @param top
+ * @return
+ */
+ def toAnnotation(top: T): AnnotationSeq
+
+ /** Called by [[chisel3.stage.phases.AspectPhase]] to resolve this Aspect into annotations
+ * @param top
+ * @return
+ */
+ private[chisel3] def resolveAspect(top: RawModule): AnnotationSeq = {
+ toAnnotation(top.asInstanceOf[T])
+ }
+}
+
+/** Holds utility functions for Aspect stuff */
+object Aspect {
+
+ /** Converts elaborated Chisel components to FIRRTL modules
+ * @param chiselIR
+ * @return
+ */
+ def getFirrtl(chiselIR: chisel3.internal.firrtl.Circuit): firrtl.ir.Circuit = {
+ chisel3.internal.firrtl.Converter.convert(chiselIR)
+ }
+}
diff --git a/core/src/main/scala/chisel3/core/package.scala b/core/src/main/scala/chisel3/core/package.scala
new file mode 100644
index 00000000..92c4617b
--- /dev/null
+++ b/core/src/main/scala/chisel3/core/package.scala
@@ -0,0 +1,288 @@
+// See LICENSE for license details.
+
+package chisel3
+
+/**
+ * These definitions exist to deal with those clients that relied on chisel3.core.
+ * They are deprecated and will be removed in the future.
+ */
+package object core {
+
+ @deprecated("Use the version in chisel3._", "3.2")
+ val CompileOptions = chisel3.CompileOptions
+
+ @deprecated("Use the version in chisel3._", "3.2")
+ val Input = chisel3.Input
+ @deprecated("Use the version in chisel3._", "3.2")
+ val Output = chisel3.Output
+ @deprecated("Use the version in chisel3._", "3.2")
+ val Flipped = chisel3.Flipped
+ @deprecated("Use the version in chisel3._", "3.2")
+ val chiselTypeOf = chisel3.chiselTypeOf
+
+ @deprecated("Use the version in chisel3._", "3.2")
+ type Data = chisel3.Data
+
+ @deprecated("Use the version in chisel3._", "3.2")
+ val WireDefault = chisel3.WireDefault
+
+ @deprecated("Use the version in chisel3._", "3.2")
+ val Clock = chisel3.Clock
+ @deprecated("Use the version in chisel3._", "3.2")
+ type Clock = chisel3.Clock
+
+ @deprecated("Use the version in chisel3._", "3.2")
+ type Reset = chisel3.Reset
+
+ @deprecated("Use the version in chisel3._", "3.2")
+ type Aggregate = chisel3.Aggregate
+
+ @deprecated("Use the version in chisel3._", "3.2")
+ val Vec = chisel3.Vec
+ @deprecated("Use the version in chisel3._", "3.2")
+ val VecInit = chisel3.VecInit
+ @deprecated("Use the version in chisel3._", "3.2")
+ type Vec[T <: Data] = chisel3.Vec[T]
+ @deprecated("Use the version in chisel3._", "3.2")
+ type VecLike[T <: Data] = chisel3.VecLike[T]
+ @deprecated("Use the version in chisel3._", "3.2")
+ type Bundle = chisel3.Bundle
+ @deprecated("Use the version in chisel3._", "3.2")
+ type IgnoreSeqInBundle = chisel3.IgnoreSeqInBundle
+ @deprecated("Use the version in chisel3._", "3.2")
+ type Record = chisel3.Record
+
+ @deprecated("Use the version in chisel3._", "3.2")
+ val assert = chisel3.assert
+
+ @deprecated("Use the version in chisel3._", "3.2")
+ type Element = chisel3.Element
+ @deprecated("Use the version in chisel3._", "3.2")
+ type Bits = chisel3.Bits
+
+ // These provide temporary compatibility for those who foolishly imported from chisel3.core
+ @deprecated("Avoid importing from chisel3.core, these are not public APIs and may change at any time. " +
+ " Use chisel3.RawModule instead. This alias will be removed in 3.3.", "since the beginning of time")
+ type RawModule = chisel3.RawModule
+ @deprecated("Avoid importing from chisel3.core, these are not public APIs and may change at any time. " +
+ "Use chisel3.MultiIOModule instead. This alias will be removed in 3.3.", "since the beginning of time")
+ type MultiIOModule = chisel3.MultiIOModule
+ @deprecated("Avoid importing from chisel3.core, these are not public APIs and may change at any time. " +
+ " Use chisel3.RawModule instead. This alias will be removed in 3.3.", "since the beginning of time")
+ type UserModule = chisel3.RawModule
+ @deprecated("Avoid importing from chisel3.core, these are not public APIs and may change at any time. " +
+ "Use chisel3.MultiIOModule instead. This alias will be removed in 3.3.", "since the beginning of time")
+ type ImplicitModule = chisel3.MultiIOModule
+
+ @deprecated("Use the version in chisel3._", "3.2")
+ val Bits = chisel3.Bits
+ @deprecated("Use the version in chisel3._", "3.2")
+ type Num[T <: chisel3.Data] = chisel3.Num[T]
+ @deprecated("Use the version in chisel3._", "3.2")
+ type UInt = chisel3.UInt
+ @deprecated("Use the version in chisel3._", "3.2")
+ val UInt = chisel3.UInt
+ @deprecated("Use the version in chisel3._", "3.2")
+ type SInt = chisel3.SInt
+ @deprecated("Use the version in chisel3._", "3.2")
+ val SInt = chisel3.SInt
+ @deprecated("Use the version in chisel3._", "3.2")
+ type Bool = chisel3.Bool
+ @deprecated("Use the version in chisel3._", "3.2")
+ val Bool = chisel3.Bool
+ @deprecated("Use the version in chisel3._", "3.2")
+ val Mux = chisel3.Mux
+
+ @deprecated("Use the version in chisel3._", "3.2")
+ type BlackBox = chisel3.BlackBox
+
+ @deprecated("Use the version in chisel3._", "3.2")
+ val Mem = chisel3.Mem
+ @deprecated("Use the version in chisel3._", "3.2")
+ type MemBase[T <: chisel3.Data] = chisel3.MemBase[T]
+ @deprecated("Use the version in chisel3._", "3.2")
+ type Mem[T <: chisel3.Data] = chisel3.Mem[T]
+ @deprecated("Use the version in chisel3._", "3.2")
+ val SyncReadMem = chisel3.SyncReadMem
+ @deprecated("Use the version in chisel3._", "3.2")
+ type SyncReadMem[T <: chisel3.Data] = chisel3.SyncReadMem[T]
+
+ @deprecated("Use the version in chisel3._", "3.2")
+ val Module = chisel3.Module
+ @deprecated("Use the version in chisel3._", "3.2")
+ type Module = chisel3.Module
+
+ @deprecated("Use the version in chisel3._", "3.2")
+ val printf = chisel3.printf
+
+ @deprecated("Use the version in chisel3._", "3.2")
+ val RegNext = chisel3.RegNext
+ @deprecated("Use the version in chisel3._", "3.2")
+ val RegInit = chisel3.RegInit
+ @deprecated("Use the version in chisel3._", "3.2")
+ val Reg = chisel3.Reg
+
+ @deprecated("Use the version in chisel3._", "3.2")
+ val when = chisel3.when
+ @deprecated("Use the version in chisel3._", "3.2")
+ type WhenContext = chisel3.WhenContext
+
+ @deprecated("Use the version in chisel3._", "3.2")
+ type Printable = chisel3.Printable
+ @deprecated("Use the version in chisel3._", "3.2")
+ val Printable = chisel3.Printable
+ @deprecated("Use the version in chisel3._", "3.2")
+ type Printables = chisel3.Printables
+ @deprecated("Use the version in chisel3._", "3.2")
+ val Printables = chisel3.Printables
+ @deprecated("Use the version in chisel3._", "3.2")
+ type PString = chisel3.PString
+ @deprecated("Use the version in chisel3._", "3.2")
+ val PString = chisel3.PString
+ @deprecated("Use the version in chisel3._", "3.2")
+ type FirrtlFormat = chisel3.FirrtlFormat
+ @deprecated("Use the version in chisel3._", "3.2")
+ val FirrtlFormat = chisel3.FirrtlFormat
+ @deprecated("Use the version in chisel3._", "3.2")
+ type Decimal = chisel3.Decimal
+ @deprecated("Use the version in chisel3._", "3.2")
+ val Decimal = chisel3.Decimal
+ @deprecated("Use the version in chisel3._", "3.2")
+ type Hexadecimal = chisel3.Hexadecimal
+ val Hexadecimal = chisel3.Hexadecimal
+ @deprecated("Use the version in chisel3._", "3.2")
+ type Binary = chisel3.Binary
+ @deprecated("Use the version in chisel3._", "3.2")
+ val Binary = chisel3.Binary
+ @deprecated("Use the version in chisel3._", "3.2")
+ type Character = chisel3.Character
+ @deprecated("Use the version in chisel3._", "3.2")
+ val Character = chisel3.Character
+ @deprecated("Use the version in chisel3._", "3.2")
+ type Name = chisel3.Name
+ @deprecated("Use the version in chisel3._", "3.2")
+ val Name = chisel3.Name
+ @deprecated("Use the version in chisel3._", "3.2")
+ type FullName = chisel3.FullName
+ @deprecated("Use the version in chisel3._", "3.2")
+ val FullName = chisel3.FullName
+ @deprecated("Use the version in chisel3._", "3.2")
+ val Percent = chisel3.Percent
+
+ @deprecated("Use the version in chisel3.experimental._", "3.2")
+ type Param = chisel3.experimental.Param
+ @deprecated("Use the version in chisel3.experimental._", "3.2")
+ type IntParam = chisel3.experimental.IntParam
+ @deprecated("Use the version in chisel3.experimental._", "3.2")
+ val IntParam = chisel3.experimental.IntParam
+ @deprecated("Use the version in chisel3.experimental._", "3.2")
+ type DoubleParam = chisel3.experimental.DoubleParam
+ @deprecated("Use the version in chisel3.experimental._", "3.2")
+ val DoubleParam = chisel3.experimental.DoubleParam
+ @deprecated("Use the version in chisel3.experimental._", "3.2")
+ type StringParam = chisel3.experimental.StringParam
+ @deprecated("Use the version in chisel3.experimental._", "3.2")
+ val StringParam = chisel3.experimental.StringParam
+ @deprecated("Use the version in chisel3.experimental._", "3.2")
+ type RawParam = chisel3.experimental.RawParam
+ @deprecated("Use the version in chisel3.experimental._", "3.2")
+ val RawParam = chisel3.experimental.RawParam
+
+ @deprecated("Use the version in chisel3.experimental._", "3.2")
+ type Analog = chisel3.experimental.Analog
+ @deprecated("Use the version in chisel3.experimental._", "3.2")
+ val Analog = chisel3.experimental.Analog
+
+ @deprecated("Use the version in chisel3._", "3.2")
+ implicit class fromIntToWidth(int: Int) extends chisel3.fromIntToWidth(int)
+
+ @deprecated("Use the version in chisel3.experimental._", "3.2")
+ val attach = chisel3.experimental.attach
+
+ @deprecated("Use the version in chisel3.experimental._", "3.2")
+ type EnumType = chisel3.experimental.EnumType
+ @deprecated("Use the version in chisel3.experimental._", "3.2")
+ type EnumFactory = chisel3.experimental.EnumFactory
+ @deprecated("Use the version in chisel3.experimental._", "3.2")
+ val EnumAnnotations = chisel3.experimental.EnumAnnotations
+
+ @deprecated("Use the version in chisel3._", "3.2")
+ val withClockAndReset = chisel3.withClockAndReset
+ @deprecated("Use the version in chisel3._", "3.2")
+ val withClock = chisel3.withClock
+ @deprecated("Use the version in chisel3._", "3.2")
+ val withReset = chisel3.withReset
+
+ @deprecated("Use the version in chisel3._", "3.2")
+ val dontTouch = chisel3.dontTouch
+
+ @deprecated("Use the version in chisel3.experimental._", "3.2")
+ type BaseModule = chisel3.experimental.BaseModule
+ @deprecated("Use the version in chisel3.experimental._", "3.2")
+ type ExtModule = chisel3.experimental.ExtModule
+
+ @deprecated("Use the version in chisel3.experimental._", "3.2")
+ val IO = chisel3.experimental.IO
+
+ @deprecated("Use the version in chisel3.experimental._", "3.2")
+ type FixedPoint = chisel3.experimental.FixedPoint
+ @deprecated("Use the version in chisel3.experimental._", "3.2")
+ val FixedPoint = chisel3.experimental.FixedPoint
+ @deprecated("Use the version in chisel3.experimental._", "3.2")
+ implicit class fromDoubleToLiteral(double: Double) extends experimental.FixedPoint.Implicits.fromDoubleToLiteral(double)
+ @deprecated("Use the version in chisel3.experimental._", "3.2")
+ implicit class fromIntToBinaryPoint(int: Int) extends chisel3.fromIntToBinaryPoint(int)
+ @deprecated("Use the version in chisel3.experimental._", "3.2")
+ type RunFirrtlTransform = chisel3.experimental.RunFirrtlTransform
+
+ @deprecated("Use the version in chisel3.experimental._", "3.2")
+ val annotate = chisel3.experimental.annotate
+
+ @deprecated("Use the version in chisel3.experimental._", "3.2")
+ val DataMirror = chisel3.experimental.DataMirror
+ @deprecated("Use the version in chisel3._", "3.2")
+ type ActualDirection = chisel3.ActualDirection
+ @deprecated("Use the version in chisel3._", "3.2")
+ val ActualDirection = chisel3.ActualDirection
+
+ @deprecated("Use the version in chisel3.internal._", "3.2")
+ val requireIsHardware = chisel3.internal.requireIsHardware
+ @deprecated("Use the version in chisel3.internal._", "3.2")
+ val requireIsChiselType = chisel3.internal.requireIsChiselType
+ @deprecated("Use the version in chisel3.internal._", "3.2")
+ val BiConnect = chisel3.internal.BiConnect
+ @deprecated("Use the version in chisel3.internal._", "3.2")
+ val MonoConnect = chisel3.internal.MonoConnect
+ @deprecated("Use the version in chisel3.internal._", "3.2")
+ val BindingDirection = chisel3.internal.BindingDirection
+ @deprecated("Use the version in chisel3.internal._", "3.2")
+ type Binding = chisel3.internal.Binding
+ @deprecated("Use the version in chisel3.internal._", "3.2")
+ type TopBinding = chisel3.internal.TopBinding
+ @deprecated("Use the version in chisel3.internal._", "3.2")
+ type UnconstrainedBinding = chisel3.internal.UnconstrainedBinding
+ @deprecated("Use the version in chisel3.internal._", "3.2")
+ type ConstrainedBinding = chisel3.internal.ConstrainedBinding
+ @deprecated("Use the version in chisel3.internal._", "3.2")
+ type ReadOnlyBinding = chisel3.internal.ReadOnlyBinding
+ @deprecated("Use the version in chisel3.internal._", "3.2")
+ type OpBinding = chisel3.internal.OpBinding
+ @deprecated("Use the version in chisel3.internal._", "3.2")
+ type MemoryPortBinding = chisel3.internal.MemoryPortBinding
+ @deprecated("Use the version in chisel3.internal._", "3.2")
+ type PortBinding = chisel3.internal.PortBinding
+ @deprecated("Use the version in chisel3.internal._", "3.2")
+ type RegBinding = chisel3.internal.RegBinding
+ @deprecated("Use the version in chisel3.internal._", "3.2")
+ type WireBinding = chisel3.internal.WireBinding
+ @deprecated("Use the version in chisel3.internal._", "3.2")
+ type ChildBinding = chisel3.internal.ChildBinding
+ @deprecated("Use the version in chisel3.internal._", "3.2")
+ type DontCareBinding = chisel3.internal.DontCareBinding
+ @deprecated("Use the version in chisel3.internal._", "3.2")
+ type LitBinding = chisel3.internal.LitBinding
+ @deprecated("Use the version in chisel3.internal._", "3.2")
+ type ElementLitBinding = chisel3.internal.ElementLitBinding
+ @deprecated("Use the version in chisel3.internal._", "3.2")
+ type BundleLitBinding = chisel3.internal.BundleLitBinding
+}
diff --git a/core/src/main/scala/chisel3/dontTouch.scala b/core/src/main/scala/chisel3/dontTouch.scala
new file mode 100644
index 00000000..5dfd9f19
--- /dev/null
+++ b/core/src/main/scala/chisel3/dontTouch.scala
@@ -0,0 +1,37 @@
+package chisel3
+
+import chisel3.experimental.{ChiselAnnotation, annotate, requireIsHardware}
+import firrtl.transforms.DontTouchAnnotation
+
+/** Marks that a signal should not be removed by Chisel and Firrtl optimization passes
+ *
+ * @example {{{
+ * class MyModule extends Module {
+ * val io = IO(new Bundle {
+ * val a = Input(UInt(32.W))
+ * val b = Output(UInt(32.W))
+ * })
+ * io.b := io.a
+ * val dead = io.a +% 1.U // normally dead would be pruned by DCE
+ * dontTouch(dead) // Marking it as such will preserve it
+ * }
+ * }}}
+ * @note Calling this on [[Data]] creates an annotation that Chisel emits to a separate annotations
+ * file. This file must be passed to FIRRTL independently of the `.fir` file. The execute methods
+ * in [[chisel3.Driver]] will pass the annotations to FIRRTL automatically.
+ */
+object dontTouch { // scalastyle:ignore object.name
+ /** Marks a signal to be preserved in Chisel and Firrtl
+ *
+ * @note Requires the argument to be bound to hardware
+ * @param data The signal to be marked
+ * @return Unmodified signal `data`
+ */
+ def apply[T <: Data](data: T)(implicit compileOptions: CompileOptions): T = {
+ if (compileOptions.checkSynthesizable) {
+ requireIsHardware(data, "Data marked dontTouch")
+ }
+ annotate(new ChiselAnnotation { def toFirrtl = DontTouchAnnotation(data.toNamed) })
+ data
+ }
+}
diff --git a/core/src/main/scala/chisel3/experimental/Analog.scala b/core/src/main/scala/chisel3/experimental/Analog.scala
new file mode 100644
index 00000000..37eb578d
--- /dev/null
+++ b/core/src/main/scala/chisel3/experimental/Analog.scala
@@ -0,0 +1,85 @@
+// See LICENSE for license details.
+
+package chisel3.experimental
+
+import chisel3.internal.firrtl.Width
+import chisel3.internal.sourceinfo.SourceInfo
+import chisel3.internal._
+import chisel3.{ActualDirection, Bits, CompileOptions, Data, Element, PString, Printable, RawModule, SpecifiedDirection, UInt}
+
+import scala.collection.mutable
+
+/** Data type for representing bidirectional bitvectors of a given width
+ *
+ * Analog support is limited to allowing wiring up of Verilog BlackBoxes with bidirectional (inout)
+ * pins. There is currently no support for reading or writing of Analog types within Chisel code.
+ *
+ * Given that Analog is bidirectional, it is illegal to assign a direction to any Analog type. It
+ * is legal to "flip" the direction (since Analog can be a member of aggregate types) which has no
+ * effect.
+ *
+ * Analog types are generally connected using the bidirectional [[attach]] mechanism, but also
+ * support limited bulkconnect `<>`. Analog types are only allowed to be bulk connected *once* in a
+ * given module. This is to prevent any surprising consequences of last connect semantics.
+ *
+ * @note This API is experimental and subject to change
+ */
+final class Analog private (private[chisel3] val width: Width) extends Element {
+ require(width.known, "Since Analog is only for use in BlackBoxes, width must be known")
+
+ override def toString: String = {
+ s"Analog$width$bindingToString"
+ }
+
+ private[chisel3] override def typeEquivalent(that: Data): Boolean =
+ that.isInstanceOf[Analog] && this.width == that.width
+
+ override def litOption: Option[BigInt] = None
+
+ def cloneType: this.type = new Analog(width).asInstanceOf[this.type]
+
+ // Used to enforce single bulk connect of Analog types, multi-attach is still okay
+ // Note that this really means 1 bulk connect per Module because a port can
+ // be connected in the parent module as well
+ private[chisel3] val biConnectLocs = mutable.Map.empty[RawModule, SourceInfo]
+
+ // Define setter/getter pairing
+ // Analog can only be bound to Ports and Wires (and Unbound)
+ private[chisel3] override def bind(target: Binding, parentDirection: SpecifiedDirection) {
+ SpecifiedDirection.fromParent(parentDirection, specifiedDirection) match {
+ case SpecifiedDirection.Unspecified | SpecifiedDirection.Flip =>
+ case x => throwException(s"Analog may not have explicit direction, got '$x'")
+ }
+ val targetTopBinding = target match {
+ case target: TopBinding => target
+ case ChildBinding(parent) => parent.topBinding
+ // See https://github.com/freechipsproject/chisel3/pull/946
+ case SampleElementBinding(parent) => parent.topBinding
+ }
+
+ targetTopBinding match {
+ case _: WireBinding | _: PortBinding => direction = ActualDirection.Bidirectional(ActualDirection.Default)
+ case x => throwException(s"Analog can only be Ports and Wires, not '$x'")
+ }
+ binding = target
+ }
+
+ override def do_asUInt(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): UInt =
+ throwException("Analog does not support asUInt")
+
+ private[chisel3] override def connectFromBits(that: Bits)(implicit sourceInfo: SourceInfo,
+ compileOptions: CompileOptions): Unit = {
+ throwException("Analog does not support connectFromBits")
+ }
+
+ def toPrintable: Printable = PString("Analog")
+}
+
+/** Object that provides factory methods for [[Analog]] objects
+ *
+ * @note This API is experimental and subject to change
+ */
+object Analog {
+ def apply(width: Width): Analog = new Analog(width)
+}
+
diff --git a/core/src/main/scala/chisel3/experimental/package.scala b/core/src/main/scala/chisel3/experimental/package.scala
new file mode 100644
index 00000000..985f7715
--- /dev/null
+++ b/core/src/main/scala/chisel3/experimental/package.scala
@@ -0,0 +1,140 @@
+// See LICENSE for license details.
+
+package chisel3
+
+/** Package for experimental features, which may have their API changed, be removed, etc.
+ *
+ * Because its contents won't necessarily have the same level of stability and support as
+ * non-experimental, you must explicitly import this package to use its contents.
+ */
+package object experimental { // scalastyle:ignore object.name
+ import scala.language.implicitConversions
+ import chisel3.internal.BaseModule
+
+ // Implicit conversions for BlackBox Parameters
+ implicit def fromIntToIntParam(x: Int): IntParam = IntParam(BigInt(x))
+ implicit def fromLongToIntParam(x: Long): IntParam = IntParam(BigInt(x))
+ implicit def fromBigIntToIntParam(x: BigInt): IntParam = IntParam(x)
+ implicit def fromDoubleToDoubleParam(x: Double): DoubleParam = DoubleParam(x)
+ implicit def fromStringToStringParam(x: String): StringParam = StringParam(x)
+
+ type ChiselEnum = EnumFactory
+
+ @deprecated("Use the version in chisel3._", "3.2")
+ val withClockAndReset = chisel3.withClockAndReset
+ @deprecated("Use the version in chisel3._", "3.2")
+ val withClock = chisel3.withClock
+ @deprecated("Use the version in chisel3._", "3.2")
+ val withReset = chisel3.withReset
+
+ // Rocket Chip-style clonemodule
+
+ /** A record containing the results of CloneModuleAsRecord
+ * The apply method is retrieves the element with the supplied name.
+ */
+ type ClonePorts = BaseModule.ClonePorts
+
+ object CloneModuleAsRecord {
+ /** Clones an existing module and returns a record of all its top-level ports.
+ * Each element of the record is named with a string matching the
+ * corresponding port's name and shares the port's type.
+ * @example {{{
+ * val q1 = Module(new Queue(UInt(32.W), 2))
+ * val q2_io = CloneModuleAsRecord(q1)("io").asInstanceOf[q1.io.type]
+ * q2_io.enq <> q1.io.deq
+ * }}}
+ */
+ def apply(proto: BaseModule)(implicit sourceInfo: chisel3.internal.sourceinfo.SourceInfo, compileOptions: CompileOptions): ClonePorts = { // scalastyle:ignore line.size.limit
+ BaseModule.cloneIORecord(proto)
+ }
+ }
+
+ val requireIsHardware = chisel3.internal.requireIsHardware
+ val requireIsChiselType = chisel3.internal.requireIsChiselType
+ type Direction = ActualDirection
+ val Direction = ActualDirection
+
+ implicit class ChiselRange(val sc: StringContext) extends AnyVal {
+
+ import scala.language.experimental.macros
+
+ /** Specifies a range using mathematical range notation. Variables can be interpolated using
+ * standard string interpolation syntax.
+ * @example {{{
+ * UInt(range"[0, 2)")
+ * UInt(range"[0, \$myInt)")
+ * UInt(range"[0, \${myInt + 2})")
+ * }}}
+ */
+ def range(args: Any*): chisel3.internal.firrtl.IntervalRange = macro chisel3.internal.RangeTransform.apply
+ }
+
+ class dump extends chisel3.internal.naming.dump // scalastyle:ignore class.name
+ class treedump extends chisel3.internal.naming.treedump // scalastyle:ignore class.name
+ /** Experimental macro for naming Chisel hardware values
+ *
+ * By default, Chisel uses reflection for naming which only works for public fields of `Bundle`
+ * and `Module` classes. Applying this macro annotation to a `class` or `object` enables Chisel
+ * to name any hardware values within the annotated `class` or `object.
+ *
+ * @example {{{
+ * import chisel3._
+ * import chisel3.experimental.chiselName
+ *
+ * @chiselName
+ * class MyModule extends Module {
+ * val io = IO(new Bundle {
+ * val in = Input(UInt(8.W))
+ * val out = Output(UInt(8.W))
+ * })
+ * def createReg(): Unit = {
+ * // @chiselName allows Chisel to name this Reg
+ * val myReg = RegInit(io.in)
+ * io.out := myReg
+ * }
+ * createReg()
+ * }
+ * }}}
+ */
+ class chiselName extends chisel3.internal.naming.chiselName // scalastyle:ignore class.name
+ /** Do not name instances of this type in [[chiselName]]
+ *
+ * By default, `chiselName` will include `val` names of instances of annotated classes as a
+ * prefix in final naming. Mixing in this trait to a `class`, `object`, or anonymous `class`
+ * instances will exclude the `val` name from `chiselName` naming.
+ *
+ * @example {{{
+ * import chisel3._
+ * import chisel3.experimental.{chiselName, NoChiselNamePrefix}
+ *
+ * // Note that this is not a Module
+ * @chiselName
+ * class Counter(w: Int) {
+ * val myReg = RegInit(0.U(w.W))
+ * myReg := myReg + 1.U
+ * }
+ *
+ * @chiselName
+ * class MyModule extends Module {
+ * val io = IO(new Bundle {
+ * val out = Output(UInt(8.W))
+ * })
+ * // Name of myReg will be "counter0_myReg"
+ * val counter0 = new Counter(8)
+ * // Name of myReg will be "myReg"
+ * val counter1 = new Counter(8) with NoChiselNamePrefix
+ * io.out := counter0.myReg + counter1.myReg
+ * }
+ * }}}
+ */
+ trait NoChiselNamePrefix
+
+ object BundleLiterals {
+ implicit class AddBundleLiteralConstructor[T <: Bundle](x: T) {
+ //scalastyle:off method.name
+ def Lit(elems: (T => (Data, Data))*): T = {
+ x._makeLit(elems: _*)
+ }
+ }
+ }
+}
diff --git a/core/src/main/scala/chisel3/internal/BiConnect.scala b/core/src/main/scala/chisel3/internal/BiConnect.scala
new file mode 100644
index 00000000..6b4c1070
--- /dev/null
+++ b/core/src/main/scala/chisel3/internal/BiConnect.scala
@@ -0,0 +1,333 @@
+// See LICENSE for license details.
+
+package chisel3.internal
+
+import chisel3._
+import chisel3.experimental.{Analog, BaseModule, attach}
+import chisel3.internal.Builder.pushCommand
+import chisel3.internal.firrtl.{Connect, DefInvalid}
+import scala.language.experimental.macros
+import chisel3.internal.sourceinfo._
+
+/**
+* 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.
+*
+*/
+
+private[chisel3] object BiConnect {
+ // scalastyle:off method.name public.methods.have.type
+ // These are all the possible exceptions that can be thrown.
+ // 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 Record missing field ($field).")
+ def MissingRightFieldException(field: String) =
+ BiConnectException(s": Right Record missing field ($field).")
+ def MismatchedException(left: String, right: String) =
+ BiConnectException(s": Left ($left) and Right ($right) have different types.")
+ def AttachAlreadyBulkConnectedException(sourceInfo: SourceInfo) =
+ BiConnectException(sourceInfo.makeMessage(": Analog previously bulk connected at " + _))
+ def DontCareCantBeSink =
+ BiConnectException(": DontCare cannot be a connection sink (LHS)")
+ // scalastyle:on method.name public.methods.have.type
+
+ /** 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, connectCompileOptions: CompileOptions, left: Data, right: Data, context_mod: RawModule): Unit = { // scalastyle:ignore line.size.limit cyclomatic.complexity method.length
+ (left, right) match {
+ // Handle element case (root case)
+ case (left_a: Analog, right_a: Analog) =>
+ try {
+ markAnalogConnected(sourceInfo, left_a, context_mod)
+ markAnalogConnected(sourceInfo, right_a, context_mod)
+ } catch { // convert attach exceptions to BiConnectExceptions
+ case attach.AttachException(message) => throw BiConnectException(message)
+ }
+ attach.impl(Seq(left_a, right_a), context_mod)(sourceInfo)
+ case (left_a: Analog, DontCare) =>
+ try {
+ markAnalogConnected(sourceInfo, left_a, context_mod)
+ } catch { // convert attach exceptions to BiConnectExceptions
+ case attach.AttachException(message) => throw BiConnectException(message)
+ }
+ pushCommand(DefInvalid(sourceInfo, left_a.lref))
+ case (DontCare, right_a: Analog) => connect(sourceInfo, connectCompileOptions, right, left, context_mod)
+ case (left_e: Element, right_e: Element) => {
+ elemConnect(sourceInfo, connectCompileOptions, 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 {
+ implicit val compileOptions = connectCompileOptions
+ connect(sourceInfo, connectCompileOptions, left_v(idx), right_v(idx), context_mod)
+ } catch {
+ case BiConnectException(message) => throw BiConnectException(s"($idx)$message")
+ }
+ }
+ }
+ // Handle Vec connected to DontCare
+ case (left_v: Vec[Data@unchecked], DontCare) => {
+ for (idx <- 0 until left_v.length) {
+ try {
+ implicit val compileOptions = connectCompileOptions
+ connect(sourceInfo, connectCompileOptions, left_v(idx), right, context_mod)
+ } catch {
+ case BiConnectException(message) => throw BiConnectException(s"($idx)$message")
+ }
+ }
+ }
+ // Handle DontCare connected to Vec
+ case (DontCare, right_v: Vec[Data@unchecked]) => {
+ for (idx <- 0 until right_v.length) {
+ try {
+ implicit val compileOptions = connectCompileOptions
+ connect(sourceInfo, connectCompileOptions, left, right_v(idx), context_mod)
+ } catch {
+ case BiConnectException(message) => throw BiConnectException(s"($idx)$message")
+ }
+ }
+ }
+ // Handle Records defined in Chisel._ code (change to NotStrict)
+ case (left_r: Record, right_r: Record) => (left_r.compileOptions, right_r.compileOptions) match {
+ case (ExplicitCompileOptions.NotStrict, _) =>
+ left_r.bulkConnect(right_r)(sourceInfo, ExplicitCompileOptions.NotStrict)
+ case (_, ExplicitCompileOptions.NotStrict) =>
+ left_r.bulkConnect(right_r)(sourceInfo, ExplicitCompileOptions.NotStrict)
+ case _ => recordConnect(sourceInfo, connectCompileOptions, left_r, right_r, context_mod)
+ }
+
+ // Handle Records connected to DontCare (change to NotStrict)
+ case (left_r: Record, DontCare) =>
+ left_r.compileOptions match {
+ case ExplicitCompileOptions.NotStrict =>
+ left.bulkConnect(right)(sourceInfo, ExplicitCompileOptions.NotStrict)
+ case _ =>
+ // For each field in left, descend with right
+ for ((field, left_sub) <- left_r.elements) {
+ try {
+ connect(sourceInfo, connectCompileOptions, left_sub, right, context_mod)
+ } catch {
+ case BiConnectException(message) => throw BiConnectException(s".$field$message")
+ }
+ }
+ }
+ case (DontCare, right_r: Record) =>
+ right_r.compileOptions match {
+ case ExplicitCompileOptions.NotStrict =>
+ left.bulkConnect(right)(sourceInfo, ExplicitCompileOptions.NotStrict)
+ case _ =>
+ // For each field in left, descend with right
+ for ((field, right_sub) <- right_r.elements) {
+ try {
+ connect(sourceInfo, connectCompileOptions, left, right_sub, context_mod)
+ } 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)
+ }
+ }
+
+ // Do connection of two Records
+ def recordConnect(sourceInfo: SourceInfo,
+ connectCompileOptions: CompileOptions,
+ left_r: Record,
+ right_r: Record,
+ context_mod: RawModule): Unit = {
+ // Verify right has no extra fields that left doesn't have
+ for((field, right_sub) <- right_r.elements) {
+ if(!left_r.elements.isDefinedAt(field)) {
+ if (connectCompileOptions.connectFieldsMustMatch) {
+ throw MissingLeftFieldException(field)
+ }
+ }
+ }
+ // For each field in left, descend with right
+ for((field, left_sub) <- left_r.elements) {
+ try {
+ right_r.elements.get(field) match {
+ case Some(right_sub) => connect(sourceInfo, connectCompileOptions, left_sub, right_sub, context_mod)
+ case None => {
+ if (connectCompileOptions.connectFieldsMustMatch) {
+ throw MissingRightFieldException(field)
+ }
+ }
+ }
+ } catch {
+ case BiConnectException(message) => throw BiConnectException(s".$field$message")
+ }
+ }
+ }
+
+
+ // 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 = {
+ // Source and sink are ambiguous in the case of a Bi/Bulk Connect (<>).
+ // If either is a DontCareBinding, just issue a DefInvalid for the other,
+ // otherwise, issue a Connect.
+ (left.topBinding, right.topBinding) match {
+ case (lb: DontCareBinding, _) => pushCommand(DefInvalid(sourceInfo, right.lref))
+ case (_, rb: DontCareBinding) => pushCommand(DefInvalid(sourceInfo, left.lref))
+ case (_, _) => 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 = {
+ // Source and sink are ambiguous in the case of a Bi/Bulk Connect (<>).
+ // If either is a DontCareBinding, just issue a DefInvalid for the other,
+ // otherwise, issue a Connect.
+ (left.topBinding, right.topBinding) match {
+ case (lb: DontCareBinding, _) => pushCommand(DefInvalid(sourceInfo, right.lref))
+ case (_, rb: DontCareBinding) => pushCommand(DefInvalid(sourceInfo, left.lref))
+ case (_, _) => 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, connectCompileOptions: CompileOptions, left: Element, right: Element, context_mod: RawModule): Unit = { // scalastyle:ignore line.size.limit cyclomatic.complexity method.length
+ import BindingDirection.{Internal, 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: BaseModule = left.topBinding.location.getOrElse(context_mod)
+ val right_mod: BaseModule = right.topBinding.location.getOrElse(context_mod)
+
+ val left_direction = BindingDirection.from(left.topBinding, left.direction)
+ val right_direction = BindingDirection.from(right.topBinding, right.direction)
+
+ // 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): @unchecked) match {
+ // CURRENT MOD CHILD MOD
+ case (Input, Input) => issueConnectL2R(left, right)
+ case (Internal, Input) => issueConnectL2R(left, right)
+
+ case (Output, Output) => issueConnectR2L(left, right)
+ case (Internal, Output) => issueConnectR2L(left, right)
+
+ case (Input, Output) => throw BothDriversException
+ case (Output, Input) => throw NeitherDriverException
+ case (_, Internal) => 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): @unchecked) match {
+ // CHILD MOD CURRENT MOD
+ case (Input, Input) => issueConnectR2L(left, right)
+ case (Input, Internal) => issueConnectR2L(left, right)
+
+ case (Output, Output) => issueConnectL2R(left, right)
+ case (Output, Internal) => issueConnectL2R(left, right)
+
+ case (Input, Output) => throw NeitherDriverException
+ case (Output, Input) => throw BothDriversException
+ case (Internal, _) => 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): @unchecked) match {
+ // CURRENT MOD CURRENT MOD
+ case (Input, Output) => issueConnectL2R(left, right)
+ case (Input, Internal) => issueConnectL2R(left, right)
+ case (Internal, Output) => issueConnectL2R(left, right)
+
+ case (Output, Input) => issueConnectR2L(left, right)
+ case (Output, Internal) => issueConnectR2L(left, right)
+ case (Internal, Input) => issueConnectR2L(left, right)
+
+ case (Input, Input) => throw BothDriversException
+ case (Output, Output) => throw BothDriversException
+ case (Internal, Internal) => {
+ if (connectCompileOptions.dontAssumeDirectionality) {
+ throw UnknownDriverException
+ } else {
+ issueConnectR2L(left, right)
+ }
+ }
+ }
+ }
+
+ // 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): @unchecked) match {
+ // CHILD MOD CHILD MOD
+ case (Input, Output) => issueConnectR2L(left, right)
+ case (Output, Input) => issueConnectL2R(left, right)
+
+ case (Input, Input) => throw NeitherDriverException
+ case (Output, Output) => throw BothDriversException
+ case (_, Internal) =>
+ if (connectCompileOptions.dontAssumeDirectionality) {
+ throw UnknownRelationException
+ } else {
+ issueConnectR2L(left, right)
+ }
+ case (Internal, _) =>
+ if (connectCompileOptions.dontAssumeDirectionality) {
+ throw UnknownRelationException
+ } else {
+ issueConnectR2L(left, right)
+ }
+ }
+ }
+
+ // Not quite sure where left and right are compared to current module
+ // so just error out
+ else throw UnknownRelationException
+ }
+
+ // This function checks if analog element-level attaching is allowed, then marks the Analog as connected
+ def markAnalogConnected(implicit sourceInfo: SourceInfo, analog: Analog, contextModule: RawModule): Unit = {
+ analog.biConnectLocs.get(contextModule) match {
+ case Some(sl) => throw AttachAlreadyBulkConnectedException(sl)
+ case None => // Do nothing
+ }
+ // Mark bulk connected
+ analog.biConnectLocs(contextModule) = sourceInfo
+ }
+}
diff --git a/core/src/main/scala/chisel3/internal/Binding.scala b/core/src/main/scala/chisel3/internal/Binding.scala
new file mode 100644
index 00000000..07c44f9f
--- /dev/null
+++ b/core/src/main/scala/chisel3/internal/Binding.scala
@@ -0,0 +1,114 @@
+// See LICENSE for license details.
+
+package chisel3.internal
+
+import chisel3._
+import chisel3.experimental.BaseModule
+import chisel3.internal.firrtl.LitArg
+
+/** Requires that a node is hardware ("bound")
+ */
+object requireIsHardware {
+ def apply(node: Data, msg: String = ""): Unit = {
+ node._parent match { // Compatibility layer hack
+ case Some(x: BaseModule) => x._compatAutoWrapPorts
+ case _ =>
+ }
+ if (!node.isSynthesizable) {
+ val prefix = if (msg.nonEmpty) s"$msg " else ""
+ throw ExpectedHardwareException(s"$prefix'$node' must be hardware, " +
+ "not a bare Chisel type. Perhaps you forgot to wrap it in Wire(_) or IO(_)?")
+ }
+ }
+}
+
+/** Requires that a node is a chisel type (not hardware, "unbound")
+ */
+object requireIsChiselType {
+ def apply(node: Data, msg: String = ""): Unit = if (node.isSynthesizable) {
+ val prefix = if (msg.nonEmpty) s"$msg " else ""
+ throw ExpectedChiselTypeException(s"$prefix'$node' must be a Chisel type, not hardware")
+ }
+}
+
+// Element only direction used for the Binding system only.
+private[chisel3] sealed abstract class BindingDirection
+private[chisel3] object BindingDirection {
+ /** Internal type or wire
+ */
+ case object Internal extends BindingDirection
+ /** Module port with output direction
+ */
+ case object Output extends BindingDirection
+ /** Module port with input direction
+ */
+ case object Input extends BindingDirection
+
+ /** Determine the BindingDirection of an Element given its top binding and resolved direction.
+ */
+ def from(binding: TopBinding, direction: ActualDirection): BindingDirection = {
+ binding match {
+ case PortBinding(_) => direction match {
+ case ActualDirection.Output => Output
+ case ActualDirection.Input => Input
+ case dir => throw new RuntimeException(s"Unexpected port element direction '$dir'")
+ }
+ case _ => Internal
+ }
+ }
+}
+
+// Location refers to 'where' in the Module hierarchy this lives
+sealed trait Binding {
+ def location: Option[BaseModule]
+}
+// Top-level binding representing hardware, not a pointer to another binding (like ChildBinding)
+sealed trait TopBinding extends Binding
+
+// Constrained-ness refers to whether 'bound by Module boundaries'
+// An unconstrained binding, like a literal, can be read by everyone
+sealed trait UnconstrainedBinding extends TopBinding {
+ def location: Option[BaseModule] = None
+}
+// A constrained binding can only be read/written by specific modules
+// Location will track where this Module is, and the bound object can be referenced in FIRRTL
+sealed trait ConstrainedBinding extends TopBinding {
+ def enclosure: BaseModule
+ def location: Option[BaseModule] = {
+ // If an aspect is present, return the aspect module. Otherwise, return the enclosure module
+ // This allows aspect modules to pretend to be enclosed modules for connectivity checking,
+ // inside vs outside instance checking, etc.
+ Builder.aspectModule(enclosure) match {
+ case None => Some(enclosure)
+ case Some(aspect) => Some(aspect)
+ }
+ }
+}
+
+// A binding representing a data that cannot be (re)assigned to.
+sealed trait ReadOnlyBinding extends TopBinding
+
+// TODO(twigg): Ops between unenclosed nodes can also be unenclosed
+// However, Chisel currently binds all op results to a module
+case class OpBinding(enclosure: RawModule) extends ConstrainedBinding with ReadOnlyBinding
+case class MemoryPortBinding(enclosure: RawModule) extends ConstrainedBinding
+case class PortBinding(enclosure: BaseModule) extends ConstrainedBinding
+case class RegBinding(enclosure: RawModule) extends ConstrainedBinding
+case class WireBinding(enclosure: RawModule) extends ConstrainedBinding
+
+case class ChildBinding(parent: Data) extends Binding {
+ def location: Option[BaseModule] = parent.topBinding.location
+}
+/** Special binding for Vec.sample_element */
+case class SampleElementBinding[T <: Data](parent: Vec[T]) extends Binding {
+ def location = parent.topBinding.location
+}
+// A DontCare element has a specific Binding, somewhat like a literal.
+// It is a source (RHS). It may only be connected/applied to sinks.
+case class DontCareBinding() extends UnconstrainedBinding
+
+sealed trait LitBinding extends UnconstrainedBinding with ReadOnlyBinding
+// Literal binding attached to a element that is not part of a Bundle.
+case class ElementLitBinding(litArg: LitArg) extends LitBinding
+// Literal binding attached to the root of a Bundle, containing literal values of its children.
+case class BundleLitBinding(litMap: Map[Data, LitArg]) extends LitBinding
diff --git a/core/src/main/scala/chisel3/internal/Builder.scala b/core/src/main/scala/chisel3/internal/Builder.scala
new file mode 100644
index 00000000..773a9ad1
--- /dev/null
+++ b/core/src/main/scala/chisel3/internal/Builder.scala
@@ -0,0 +1,452 @@
+// See LICENSE for license details.
+
+package chisel3.internal
+
+import scala.util.DynamicVariable
+import scala.collection.mutable.ArrayBuffer
+import chisel3._
+import chisel3.experimental._
+import chisel3.internal.firrtl._
+import chisel3.internal.naming._
+import _root_.firrtl.annotations.{CircuitName, ComponentName, IsMember, ModuleName, Named, ReferenceTarget}
+
+import scala.collection.mutable
+
+private[chisel3] class Namespace(keywords: Set[String]) {
+ private val names = collection.mutable.HashMap[String, Long]()
+ for (keyword <- keywords)
+ names(keyword) = 1
+
+ private def rename(n: String): String = {
+ val index = names(n)
+ val tryName = s"${n}_${index}"
+ names(n) = index + 1
+ if (this contains tryName) rename(n) else tryName
+ }
+
+ private def sanitize(s: String, leadingDigitOk: Boolean = false): String = {
+ // TODO what character set does FIRRTL truly support? using ANSI C for now
+ def legalStart(c: Char) = (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_'
+ def legal(c: Char) = legalStart(c) || (c >= '0' && c <= '9')
+ val res = s filter legal
+ val headOk = (!res.isEmpty) && (leadingDigitOk || legalStart(res.head))
+ if (headOk) res else s"_$res"
+ }
+
+ def contains(elem: String): Boolean = names.contains(elem)
+
+ // leadingDigitOk is for use in fields of Records
+ def name(elem: String, leadingDigitOk: Boolean = false): String = {
+ val sanitized = sanitize(elem, leadingDigitOk)
+ if (this contains sanitized) {
+ name(rename(sanitized))
+ } else {
+ names(sanitized) = 1
+ sanitized
+ }
+ }
+}
+
+private[chisel3] object Namespace {
+ /** Constructs an empty Namespace */
+ def empty: Namespace = new Namespace(Set.empty[String])
+}
+
+private[chisel3] class IdGen {
+ private var counter = -1L
+ def next: Long = {
+ counter += 1
+ counter
+ }
+}
+
+/** Public API to access Node/Signal names.
+ * currently, the node's name, the full path name, and references to its parent Module and component.
+ * These are only valid once the design has been elaborated, and should not be used during its construction.
+ */
+trait InstanceId {
+ def instanceName: String
+ def pathName: String
+ def parentPathName: String
+ def parentModName: String
+ /** Returns a FIRRTL Named that refers to this object in the elaborated hardware graph */
+ def toNamed: Named
+ /** Returns a FIRRTL IsMember that refers to this object in the elaborated hardware graph */
+ def toTarget: IsMember
+ /** Returns a FIRRTL IsMember that refers to the absolute path to this object in the elaborated hardware graph */
+ def toAbsoluteTarget: IsMember
+}
+
+private[chisel3] trait HasId extends InstanceId {
+ private[chisel3] def _onModuleClose: Unit = {} // scalastyle:ignore method.name
+ private[chisel3] val _parent: Option[BaseModule] = Builder.currentModule
+ _parent.foreach(_.addId(this))
+
+ private[chisel3] val _id: Long = Builder.idGen.next
+
+ // TODO: remove this, but its removal seems to cause a nasty Scala compiler crash.
+ override def hashCode: Int = super.hashCode()
+ override def equals(that: Any): Boolean = super.equals(that)
+
+ // 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[chisel3] def suggestedName: Option[String] = suggested_name
+ 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 Record)
+ 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)
+ setRef(Ref(available_name))
+ }
+
+ private var _ref: Option[Arg] = None
+ 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[chisel3] def getOptionRef: Option[Arg] = _ref
+
+ // Implementation of public methods.
+ def instanceName: String = _parent match {
+ case Some(p) => p._component match {
+ case Some(c) => _ref match {
+ case Some(arg) => arg fullName c
+ case None => suggested_name.getOrElse("??")
+ }
+ case None => throwException("signalName/pathName should be called after circuit elaboration")
+ }
+ case None => throwException("this cannot happen")
+ }
+ def pathName: String = _parent match {
+ case None => instanceName
+ case Some(p) => s"${p.pathName}.$instanceName"
+ }
+ def parentPathName: String = _parent match {
+ case Some(p) => p.pathName
+ case None => throwException(s"$instanceName doesn't have a parent")
+ }
+ def parentModName: String = _parent match {
+ case Some(p) => p.name
+ case None => throwException(s"$instanceName doesn't have a parent")
+ }
+ // TODO Should this be public?
+ protected def circuitName: String = _parent match {
+ case None => instanceName
+ case Some(p) => p.circuitName
+ }
+
+ private[chisel3] def getPublicFields(rootClass: Class[_]): Seq[java.lang.reflect.Method] = {
+ // Suggest names to nodes using runtime reflection
+ def getValNames(c: Class[_]): Set[String] = {
+ if (c == rootClass) {
+ Set()
+ } else {
+ getValNames(c.getSuperclass) ++ c.getDeclaredFields.map(_.getName)
+ }
+ }
+ val valNames = getValNames(this.getClass)
+ def isPublicVal(m: java.lang.reflect.Method) =
+ m.getParameterTypes.isEmpty && valNames.contains(m.getName) && !m.getDeclaringClass.isAssignableFrom(rootClass)
+ this.getClass.getMethods.sortWith(_.getName < _.getName).filter(isPublicVal(_))
+ }
+}
+/** Holds the implementation of toNamed for Data and MemBase */
+private[chisel3] trait NamedComponent extends HasId {
+ /** Returns a FIRRTL ComponentName that references this object
+ * @note Should not be called until circuit elaboration is complete
+ */
+ final def toNamed: ComponentName =
+ ComponentName(this.instanceName, ModuleName(this.parentModName, CircuitName(this.circuitName)))
+
+ /** Returns a FIRRTL ReferenceTarget that references this object
+ * @note Should not be called until circuit elaboration is complete
+ */
+ final def toTarget: ReferenceTarget = {
+ val name = this.instanceName
+ import _root_.firrtl.annotations.{Target, TargetToken}
+ Target.toTargetTokens(name).toList match {
+ case TargetToken.Ref(r) :: components => ReferenceTarget(this.circuitName, this.parentModName, Nil, r, components)
+ case other =>
+ throw _root_.firrtl.annotations.Target.NamedException(s"Cannot convert $name into [[ReferenceTarget]]: $other")
+ }
+ }
+
+ final def toAbsoluteTarget: ReferenceTarget = {
+ val localTarget = toTarget
+ _parent match {
+ case Some(parent) => parent.toAbsoluteTarget.ref(localTarget.ref).copy(component = localTarget.component)
+ case None => localTarget
+ }
+ }
+}
+
+// Mutable global state for chisel that can appear outside a Builder context
+private[chisel3] class ChiselContext() {
+ val idGen = new IdGen
+
+ // Record the Bundle instance, class name, method name, and reverse stack trace position of open Bundles
+ val bundleStack: ArrayBuffer[(Bundle, String, String, Int)] = ArrayBuffer()
+}
+
+private[chisel3] class DynamicContext() {
+ val globalNamespace = Namespace.empty
+ val components = ArrayBuffer[Component]()
+ val annotations = ArrayBuffer[ChiselAnnotation]()
+ var currentModule: Option[BaseModule] = None
+
+ /** Contains a mapping from a elaborated module to their aspect
+ * Set by [[ModuleAspect]]
+ */
+ val aspectModule: mutable.HashMap[BaseModule, BaseModule] = mutable.HashMap.empty[BaseModule, BaseModule]
+
+ // Set by object Module.apply before calling class Module constructor
+ // Used to distinguish between no Module() wrapping, multiple wrappings, and rewrapping
+ var readyForModuleConstr: Boolean = false
+ var whenDepth: Int = 0 // Depth of when nesting
+ var currentClock: Option[Clock] = None
+ var currentReset: Option[Reset] = None
+ val errors = new ErrorLog
+ val namingStack = new NamingStack
+}
+
+//scalastyle:off number.of.methods
+private[chisel3] object Builder {
+ // All global mutable state must be referenced via dynamicContextVar!!
+ private val dynamicContextVar = new DynamicVariable[Option[DynamicContext]](None)
+ private def dynamicContext: DynamicContext = {
+ require(dynamicContextVar.value.isDefined, "must be inside Builder context")
+ dynamicContextVar.value.get
+ }
+
+ private val chiselContext = new DynamicVariable[ChiselContext](new ChiselContext)
+
+ // Initialize any singleton objects before user code inadvertently inherits them.
+ private def initializeSingletons(): Unit = {
+ // This used to contain:
+ // val dummy = core.DontCare
+ // but this would occasionally produce hangs due to static initialization deadlock
+ // when Builder initialization collided with chisel3.package initialization of the DontCare value.
+ // See:
+ // http://ternarysearch.blogspot.com/2013/07/static-initialization-deadlock.html
+ // https://bugs.openjdk.java.net/browse/JDK-8037567
+ // https://stackoverflow.com/questions/28631656/runnable-thread-state-but-in-object-wait
+ }
+
+ def namingStackOption: Option[NamingStack] = dynamicContextVar.value.map(_.namingStack)
+
+ def idGen: IdGen = chiselContext.value.idGen
+
+ def globalNamespace: Namespace = dynamicContext.globalNamespace
+ def components: ArrayBuffer[Component] = dynamicContext.components
+ def annotations: ArrayBuffer[ChiselAnnotation] = dynamicContext.annotations
+ def namingStack: NamingStack = dynamicContext.namingStack
+
+ def currentModule: Option[BaseModule] = dynamicContextVar.value match {
+ case Some(dyanmicContext) => dynamicContext.currentModule
+ case _ => None
+ }
+ def currentModule_=(target: Option[BaseModule]): Unit = {
+ dynamicContext.currentModule = target
+ }
+ def aspectModule(module: BaseModule): Option[BaseModule] = dynamicContextVar.value match {
+ case Some(dynamicContext) => dynamicContext.aspectModule.get(module)
+ case _ => None
+ }
+ def addAspect(module: BaseModule, aspect: BaseModule): Unit = {
+ dynamicContext.aspectModule += ((module, aspect))
+ }
+ def forcedModule: BaseModule = currentModule match {
+ case Some(module) => module
+ case None => throwException(
+ "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).
+ )
+ }
+ def referenceUserModule: RawModule = {
+ currentModule match {
+ case Some(module: RawModule) =>
+ aspectModule(module) match {
+ case Some(aspect: RawModule) => aspect
+ case other => module
+ }
+ case _ => throwException(
+ "Error: Not in a RawModule. Likely cause: Missed Module() wrap, bare chisel API call, or attempting to construct hardware inside a BlackBox." // scalastyle:ignore line.size.limit
+ // A bare api call is, e.g. calling Wire() from the scala console).
+ )
+ }
+ }
+ def forcedUserModule: RawModule = currentModule match {
+ case Some(module: RawModule) => module
+ case _ => throwException(
+ "Error: Not in a UserModule. Likely cause: Missed Module() wrap, bare chisel API call, or attempting to construct hardware inside a BlackBox." // scalastyle:ignore line.size.limit
+ // A bare api call is, e.g. calling Wire() from the scala console).
+ )
+ }
+ def readyForModuleConstr: Boolean = dynamicContext.readyForModuleConstr
+ def readyForModuleConstr_=(target: Boolean): Unit = {
+ dynamicContext.readyForModuleConstr = target
+ }
+ def whenDepth: Int = dynamicContext.whenDepth
+ def whenDepth_=(target: Int): Unit = {
+ dynamicContext.whenDepth = target
+ }
+ def currentClock: Option[Clock] = dynamicContext.currentClock
+ def currentClock_=(newClock: Option[Clock]): Unit = {
+ dynamicContext.currentClock = newClock
+ }
+
+ def currentReset: Option[Reset] = dynamicContext.currentReset
+ def currentReset_=(newReset: Option[Reset]): Unit = {
+ dynamicContext.currentReset = newReset
+ }
+
+ def forcedClock: Clock = currentClock.getOrElse(
+ throwException("Error: No implicit clock.")
+ )
+ def forcedReset: Reset = currentReset.getOrElse(
+ throwException("Error: No implicit reset.")
+ )
+
+ // 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 = {
+ forcedUserModule.addCommand(c)
+ c
+ }
+ def pushOp[T <: Data](cmd: DefPrim[T]): T = {
+ // Bind each element of the returned Data to being a Op
+ cmd.id.bind(OpBinding(forcedUserModule))
+ pushCommand(cmd).id
+ }
+
+ // Called when Bundle construction begins, used to record a stack of open Bundle constructors to
+ // record candidates for Bundle autoclonetype. This is a best-effort guess.
+ // Returns the current stack of open Bundles
+ // Note: elt will NOT have finished construction, its elements cannot be accessed
+ def updateBundleStack(elt: Bundle): Seq[Bundle] = {
+ val stackElts = Thread.currentThread().getStackTrace()
+ .reverse // so stack frame numbers are deterministic across calls
+ .dropRight(2) // discard Thread.getStackTrace and updateBundleStack
+
+ // Determine where we are in the Bundle stack
+ val eltClassName = elt.getClass.getName
+ val eltStackPos = stackElts.map(_.getClassName).lastIndexOf(eltClassName)
+
+ // Prune the existing Bundle stack of closed Bundles
+ // If we know where we are in the stack, discard frames above that
+ val stackEltsTop = if (eltStackPos >= 0) eltStackPos else stackElts.size
+ val pruneLength = chiselContext.value.bundleStack.reverse.prefixLength { case (_, cname, mname, pos) =>
+ pos >= stackEltsTop || stackElts(pos).getClassName != cname || stackElts(pos).getMethodName != mname
+ }
+ chiselContext.value.bundleStack.trimEnd(pruneLength)
+
+ // Return the stack state before adding the most recent bundle
+ val lastStack = chiselContext.value.bundleStack.map(_._1).toSeq
+
+ // Append the current Bundle to the stack, if it's on the stack trace
+ if (eltStackPos >= 0) {
+ val stackElt = stackElts(eltStackPos)
+ chiselContext.value.bundleStack.append((elt, eltClassName, stackElt.getMethodName, eltStackPos))
+ }
+ // Otherwise discard the stack frame, this shouldn't fail noisily
+
+ lastStack
+ }
+
+ /** Recursively suggests names to supported "container" classes
+ * Arbitrary nestings of supported classes are allowed so long as the
+ * innermost element is of type HasId
+ * (Note: Map is Iterable[Tuple2[_,_]] and thus excluded)
+ */
+ def nameRecursively(prefix: String, nameMe: Any, namer: (HasId, String) => Unit): Unit = nameMe match {
+ case (id: HasId) => namer(id, prefix)
+ case Some(elt) => nameRecursively(prefix, elt, namer)
+ case (iter: Iterable[_]) if iter.hasDefiniteSize =>
+ for ((elt, i) <- iter.zipWithIndex) {
+ nameRecursively(s"${prefix}_${i}", elt, namer)
+ }
+ case _ => // Do nothing
+ }
+
+ def errors: ErrorLog = dynamicContext.errors
+ def error(m: => String): Unit = if (dynamicContextVar.value.isDefined) errors.error(m)
+ def warning(m: => String): Unit = if (dynamicContextVar.value.isDefined) errors.warning(m)
+ def deprecated(m: => String, location: Option[String] = None): Unit =
+ if (dynamicContextVar.value.isDefined) errors.deprecated(m, location)
+
+ /** Record an exception as an error, and throw it.
+ *
+ * @param m exception message
+ */
+ @throws(classOf[ChiselException])
+ def exception(m: => String): Unit = {
+ error(m)
+ throwException(m)
+ }
+
+ def build[T <: RawModule](f: => T): (Circuit, T) = {
+ chiselContext.withValue(new ChiselContext) {
+ 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, annotations), mod)
+ }
+ }
+ }
+ initializeSingletons()
+}
+
+/** Allows public access to the naming stack in Builder / DynamicContext, and handles invocations
+ * outside a Builder context.
+ * Necessary because naming macros expand in user code and don't have access into private[chisel3]
+ * objects.
+ */
+object DynamicNamingStack {
+ def pushContext(): NamingContextInterface = {
+ Builder.namingStackOption match {
+ case Some(namingStack) => namingStack.pushContext()
+ case None => DummyNamer
+ }
+ }
+
+ def popReturnContext[T <: Any](prefixRef: T, until: NamingContextInterface): T = {
+ until match {
+ case DummyNamer =>
+ require(Builder.namingStackOption.isEmpty,
+ "Builder context must remain stable throughout a chiselName-annotated function invocation")
+ case context: NamingContext =>
+ require(Builder.namingStackOption.isDefined,
+ "Builder context must remain stable throughout a chiselName-annotated function invocation")
+ Builder.namingStackOption.get.popContext(prefixRef, context)
+ }
+ prefixRef
+ }
+
+ def length() : Int = Builder.namingStackOption.get.length
+}
+
+/** Casts BigInt to Int, issuing an error when the input isn't representable. */
+private[chisel3] object castToInt {
+ def apply(x: BigInt, msg: String): Int = {
+ val res = x.toInt
+ require(x == res, s"$msg $x is too large to be represented as Int")
+ res
+ }
+}
diff --git a/core/src/main/scala/chisel3/internal/Error.scala b/core/src/main/scala/chisel3/internal/Error.scala
new file mode 100644
index 00000000..369da52e
--- /dev/null
+++ b/core/src/main/scala/chisel3/internal/Error.scala
@@ -0,0 +1,213 @@
+// See LICENSE for license details.
+
+package chisel3.internal
+
+import scala.annotation.tailrec
+import scala.collection.mutable.{ArrayBuffer, LinkedHashMap}
+
+class ChiselException(message: String, cause: Throwable = null) extends Exception(message, cause) {
+
+ /** Package names whose stack trace elements should be trimmed when generating a trimmed stack trace */
+ val blacklistPackages: Set[String] = Set("chisel3", "scala", "java", "sun", "sbt")
+
+ /** The object name of Chisel's internal `Builder`. Everything stack trace element after this will be trimmed. */
+ val builderName: String = chisel3.internal.Builder.getClass.getName
+
+ /** Examine a [[Throwable]], to extract all its causes. Innermost cause is first.
+ * @param throwable an exception to examine
+ * @return a sequence of all the causes with innermost cause first
+ */
+ @tailrec
+ private def getCauses(throwable: Throwable, acc: Seq[Throwable] = Seq.empty): Seq[Throwable] =
+ throwable.getCause() match {
+ case null => throwable +: acc
+ case a => getCauses(a, throwable +: acc)
+ }
+
+ /** Returns true if an exception contains */
+ private def containsBuilder(throwable: Throwable): Boolean =
+ throwable.getStackTrace().collectFirst {
+ case ste if ste.getClassName().startsWith(builderName) => throwable
+ }.isDefined
+
+ /** Examine this [[ChiselException]] and it's causes for the first [[Throwable]] that contains a stack trace including
+ * a stack trace element whose declaring class is the [[builderName]]. If no such element exists, return this
+ * [[ChiselException]].
+ */
+ private lazy val likelyCause: Throwable =
+ getCauses(this).collectFirst{ case a if containsBuilder(a) => a }.getOrElse(this)
+
+ /** For an exception, return a stack trace trimmed to user code only
+ *
+ * This does the following actions:
+ *
+ * 1. Trims the top of the stack trace while elements match [[blacklistPackages]]
+ * 2. Trims the bottom of the stack trace until an element matches [[builderName]]
+ * 3. Trims from the [[builderName]] all [[blacklistPackages]]
+ *
+ * @param throwable the exception whose stack trace should be trimmed
+ * @return an array of stack trace elements
+ */
+ private def trimmedStackTrace(throwable: Throwable): Array[StackTraceElement] = {
+ def isBlacklisted(ste: StackTraceElement) = {
+ val packageName = ste.getClassName().takeWhile(_ != '.')
+ blacklistPackages.contains(packageName)
+ }
+
+ val trimmedLeft = throwable.getStackTrace().view.dropWhile(isBlacklisted)
+ val trimmedReverse = trimmedLeft.reverse
+ .dropWhile(ste => !ste.getClassName.startsWith(builderName))
+ .dropWhile(isBlacklisted)
+ trimmedReverse.reverse.toArray
+ }
+
+ /** trims the top of the stack of elements belonging to [[blacklistPackages]]
+ * then trims the bottom elements until it reaches [[builderName]]
+ * then continues trimming elements belonging to [[blacklistPackages]]
+ */
+ @deprecated("This method will be removed in 3.4", "3.3")
+ def trimmedStackTrace: Array[StackTraceElement] = trimmedStackTrace(this)
+
+ def chiselStackTrace: String = {
+ val trimmed = trimmedStackTrace(likelyCause)
+
+ val sw = new java.io.StringWriter
+ sw.write(likelyCause.toString + "\n")
+ sw.write("\t...\n")
+ trimmed.foreach(ste => sw.write(s"\tat $ste\n"))
+ sw.write("\t... (Stack trace trimmed to user code only, rerun with --full-stacktrace if you wish to see the full stack trace)\n") // scalastyle:ignore line.size.limit
+ sw.toString
+ }
+}
+
+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[chisel3] object ErrorLog {
+ val depTag = s"[${Console.BLUE}deprecated${Console.RESET}]"
+ val warnTag = s"[${Console.YELLOW}warn${Console.RESET}]"
+ val errTag = s"[${Console.RED}error${Console.RESET}]"
+}
+
+private[chisel3] class ErrorLog {
+ /** 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
+
+ /** Log a deprecation warning message */
+ def deprecated(m: => String, location: Option[String]): Unit = {
+ val sourceLoc = location match {
+ case Some(loc) => loc
+ case None => getUserLineNumber match {
+ case Some(elt: StackTraceElement) => s"${elt.getFileName}:${elt.getLineNumber}"
+ case None => "(unknown)"
+ }
+ }
+
+ val thisEntry = (m, sourceLoc)
+ deprecations += ((thisEntry, deprecations.getOrElse(thisEntry, 0) + 1))
+ }
+
+ /** Throw an exception if any errors have yet occurred. */
+ def checkpoint(): Unit = {
+ // scalastyle:off line.size.limit regex
+ deprecations.foreach { case ((message, sourceLoc), count) =>
+ println(s"${ErrorLog.depTag} $sourceLoc ($count calls): $message")
+ }
+ errors foreach println
+
+ if (!deprecations.isEmpty) {
+ println(s"${ErrorLog.warnTag} ${Console.YELLOW}There were ${deprecations.size} deprecated function(s) used." +
+ s" These may stop compiling in a future release - you are encouraged to fix these issues.${Console.RESET}")
+ println(s"${ErrorLog.warnTag} Line numbers for deprecations reported by Chisel may be inaccurate; enable scalac compiler deprecation warnings via either of the following methods:")
+ println(s"${ErrorLog.warnTag} In the sbt interactive console, enter:")
+ println(s"""${ErrorLog.warnTag} set scalacOptions in ThisBuild ++= Seq("-unchecked", "-deprecation")""")
+ println(s"${ErrorLog.warnTag} or, in your build.sbt, add the line:")
+ println(s"""${ErrorLog.warnTag} scalacOptions := Seq("-unchecked", "-deprecation")""")
+ }
+
+ val allErrors = errors.filter(_.isFatal)
+ val allWarnings = errors.filter(!_.isFatal)
+
+ if (!allWarnings.isEmpty && !allErrors.isEmpty) {
+ println(s"${ErrorLog.errTag} There were ${Console.RED}${allErrors.size} error(s)${Console.RESET} and ${Console.YELLOW}${allWarnings.size} warning(s)${Console.RESET} during hardware elaboration.")
+ } else if (!allWarnings.isEmpty) {
+ println(s"${ErrorLog.warnTag} There were ${Console.YELLOW}${allWarnings.size} warning(s)${Console.RESET} during hardware elaboration.")
+ } else if (!allErrors.isEmpty) {
+ println(s"${ErrorLog.errTag} There were ${Console.RED}${allErrors.size} error(s)${Console.RESET} during hardware elaboration.")
+ }
+
+ if (!allErrors.isEmpty) {
+ throwException("Fatal errors during hardware elaboration")
+ } else {
+ // No fatal errors, clear accumulated warnings since they've been reported
+ errors.clear()
+ }
+ // scalastyle:on line.size.limit regex
+ }
+
+ /** Returns the best guess at the first stack frame that belongs to user code.
+ */
+ private def getUserLineNumber = {
+ def isChiselClassname(className: String): Boolean = {
+ // List of classpath prefixes that are Chisel internals and should be ignored when looking for user code
+ // utils are not part of internals and errors there can be reported
+ val chiselPrefixes = Set(
+ "java.",
+ "scala.",
+ "chisel3.internal.",
+ "chisel3.experimental.",
+ "chisel3.package$" // for some compatibility / deprecated types
+ )
+ !chiselPrefixes.filter(className.startsWith(_)).isEmpty
+ }
+
+ Thread.currentThread().getStackTrace.toList.dropWhile(
+ // Get rid of everything in Chisel core
+ ste => isChiselClassname(ste.getClassName)
+ ).headOption
+ }
+
+ private val errors = ArrayBuffer[LogEntry]()
+ private val deprecations = LinkedHashMap[(String, String), Int]()
+
+ 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/core/src/main/scala/chisel3/internal/MonoConnect.scala b/core/src/main/scala/chisel3/internal/MonoConnect.scala
new file mode 100644
index 00000000..41402021
--- /dev/null
+++ b/core/src/main/scala/chisel3/internal/MonoConnect.scala
@@ -0,0 +1,264 @@
+// See LICENSE for license details.
+
+package chisel3.internal
+
+import chisel3._
+import chisel3.experimental.{Analog, BaseModule, EnumType, FixedPoint, Interval, UnsafeEnum}
+import chisel3.internal.Builder.pushCommand
+import chisel3.internal.firrtl.{Connect, DefInvalid}
+import scala.language.experimental.macros
+import chisel3.internal.sourceinfo.SourceInfo
+
+/**
+* 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 Record 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
+*/
+
+private[chisel3] object MonoConnect {
+ // scalastyle:off method.name public.methods.have.type
+ // These are all the possible exceptions that can be thrown.
+ // 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 Record missing field ($field).")
+ def MismatchedException(sink: String, source: String) =
+ MonoConnectException(s": Sink ($sink) and Source ($source) have different types.")
+ def DontCareCantBeSink =
+ MonoConnectException(": DontCare cannot be a connection sink (LHS)")
+ def AnalogCantBeMonoSink =
+ MonoConnectException(": Analog cannot participate in a mono connection (sink - LHS)")
+ def AnalogCantBeMonoSource =
+ MonoConnectException(": Analog cannot participate in a mono connection (source - RHS)")
+ def AnalogMonoConnectionException =
+ MonoConnectException(": Analog cannot participate in a mono connection (source and sink)")
+ // scalastyle:on method.name public.methods.have.type
+
+ /** 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( //scalastyle:off cyclomatic.complexity method.length
+ sourceInfo: SourceInfo,
+ connectCompileOptions: CompileOptions,
+ sink: Data,
+ source: Data,
+ context_mod: RawModule): Unit =
+ (sink, source) match {
+
+ // Handle legal element cases, note (Bool, Bool) is caught by the first two, as Bool is a UInt
+ case (sink_e: Bool, source_e: UInt) =>
+ elemConnect(sourceInfo, connectCompileOptions, sink_e, source_e, context_mod)
+ case (sink_e: UInt, source_e: Bool) =>
+ elemConnect(sourceInfo, connectCompileOptions, sink_e, source_e, context_mod)
+ case (sink_e: UInt, source_e: UInt) =>
+ elemConnect(sourceInfo, connectCompileOptions, sink_e, source_e, context_mod)
+ case (sink_e: SInt, source_e: SInt) =>
+ elemConnect(sourceInfo, connectCompileOptions, sink_e, source_e, context_mod)
+ case (sink_e: FixedPoint, source_e: FixedPoint) =>
+ elemConnect(sourceInfo, connectCompileOptions, sink_e, source_e, context_mod)
+ case (sink_e: Interval, source_e: Interval) =>
+ elemConnect(sourceInfo, connectCompileOptions, sink_e, source_e, context_mod)
+ case (sink_e: Clock, source_e: Clock) =>
+ elemConnect(sourceInfo, connectCompileOptions, sink_e, source_e, context_mod)
+ case (sink_e: AsyncReset, source_e: AsyncReset) =>
+ elemConnect(sourceInfo, connectCompileOptions, sink_e, source_e, context_mod)
+ case (sink_e: ResetType, source_e: Reset) =>
+ elemConnect(sourceInfo, connectCompileOptions, sink_e, source_e, context_mod)
+ case (sink_e: EnumType, source_e: UnsafeEnum) =>
+ elemConnect(sourceInfo, connectCompileOptions, sink_e, source_e, context_mod)
+ case (sink_e: EnumType, source_e: EnumType) if sink_e.typeEquivalent(source_e) =>
+ elemConnect(sourceInfo, connectCompileOptions, sink_e, source_e, context_mod)
+ case (sink_e: UnsafeEnum, source_e: UInt) =>
+ elemConnect(sourceInfo, connectCompileOptions, sink_e, source_e, context_mod)
+
+ // 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 {
+ implicit val compileOptions = connectCompileOptions
+ connect(sourceInfo, connectCompileOptions, sink_v(idx), source_v(idx), context_mod)
+ } catch {
+ case MonoConnectException(message) => throw MonoConnectException(s"($idx)$message")
+ }
+ }
+ // Handle Vec connected to DontCare. Apply the DontCare to individual elements.
+ case (sink_v: Vec[Data @unchecked], DontCare) =>
+ for(idx <- 0 until sink_v.length) {
+ try {
+ implicit val compileOptions = connectCompileOptions
+ connect(sourceInfo, connectCompileOptions, sink_v(idx), source, context_mod)
+ } catch {
+ case MonoConnectException(message) => throw MonoConnectException(s"($idx)$message")
+ }
+ }
+
+ // Handle Record case
+ case (sink_r: Record, source_r: Record) =>
+ // For each field, descend with right
+ for((field, sink_sub) <- sink_r.elements) {
+ try {
+ source_r.elements.get(field) match {
+ case Some(source_sub) => connect(sourceInfo, connectCompileOptions, sink_sub, source_sub, context_mod)
+ case None => {
+ if (connectCompileOptions.connectFieldsMustMatch) {
+ throw MissingFieldException(field)
+ }
+ }
+ }
+ } catch {
+ case MonoConnectException(message) => throw MonoConnectException(s".$field$message")
+ }
+ }
+ // Handle Record connected to DontCare. Apply the DontCare to individual elements.
+ case (sink_r: Record, DontCare) =>
+ // For each field, descend with right
+ for((field, sink_sub) <- sink_r.elements) {
+ try {
+ connect(sourceInfo, connectCompileOptions, sink_sub, source, context_mod)
+ } catch {
+ case MonoConnectException(message) => throw MonoConnectException(s".$field$message")
+ }
+ }
+
+ // Source is DontCare - it may be connected to anything. It generates a defInvalid for the sink.
+ case (sink, DontCare) => pushCommand(DefInvalid(sourceInfo, sink.lref))
+ // DontCare as a sink is illegal.
+ case (DontCare, _) => throw DontCareCantBeSink
+ // Analog is illegal in mono connections.
+ case (_: Analog, _:Analog) => throw AnalogMonoConnectionException
+ // Analog is illegal in mono connections.
+ case (_: Analog, _) => throw AnalogCantBeMonoSink
+ // Analog is illegal in mono connections.
+ case (_, _: Analog) => throw AnalogCantBeMonoSource
+ // 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 = {
+ // If the source is a DontCare, generate a DefInvalid for the sink,
+ // otherwise, issue a Connect.
+ source.topBinding match {
+ case b: DontCareBinding => pushCommand(DefInvalid(sourceInfo, sink.lref))
+ case _ => 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, connectCompileOptions: CompileOptions, sink: Element, source: Element, context_mod: RawModule): Unit = { // scalastyle:ignore line.size.limit
+ import BindingDirection.{Internal, 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: BaseModule = sink.topBinding.location.getOrElse(throw UnwritableSinkException)
+ val source_mod: BaseModule = source.topBinding.location.getOrElse(context_mod)
+
+ val sink_direction = BindingDirection.from(sink.topBinding, sink.direction)
+ val source_direction = BindingDirection.from(source.topBinding, source.direction)
+
+ // 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): @unchecked) match {
+ // SINK SOURCE
+ // CURRENT MOD CURRENT MOD
+ case (Output, _) => issueConnect(sink, source)
+ case (Internal, _) => issueConnect(sink, source)
+ case (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): @unchecked) match {
+ // SINK SOURCE
+ // CURRENT MOD CHILD MOD
+ case (Internal, Output) => issueConnect(sink, source)
+ case (Internal, Input) => issueConnect(sink, source)
+ case (Output, Output) => issueConnect(sink, source)
+ case (Output, Input) => issueConnect(sink, source)
+ case (_, Internal) => {
+ if (!(connectCompileOptions.dontAssumeDirectionality)) {
+ issueConnect(sink, source)
+ } else {
+ throw UnreadableSourceException
+ }
+ }
+ case (Input, Output) if (!(connectCompileOptions.dontTryConnectionsSwapped)) => issueConnect(source, sink) // scalastyle:ignore line.size.limit
+ case (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): @unchecked) match {
+ // SINK SOURCE
+ // CHILD MOD CURRENT MOD
+ case (Input, _) => issueConnect(sink, source)
+ case (Output, _) => throw UnwritableSinkException
+ case (Internal, _) => 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): @unchecked) match {
+ // SINK SOURCE
+ // CHILD MOD CHILD MOD
+ case (Input, Input) => issueConnect(sink, source)
+ case (Input, Output) => issueConnect(sink, source)
+ case (Output, _) => throw UnwritableSinkException
+ case (_, Internal) => {
+ if (!(connectCompileOptions.dontAssumeDirectionality)) {
+ issueConnect(sink, source)
+ } else {
+ throw UnreadableSourceException
+ }
+ }
+ case (Internal, _) => throw UnwritableSinkException
+ }
+ }
+
+ // Not quite sure where left and right are compared to current module
+ // so just error out
+ else throw UnknownRelationException
+ }
+}
diff --git a/core/src/main/scala/chisel3/internal/Namer.scala b/core/src/main/scala/chisel3/internal/Namer.scala
new file mode 100644
index 00000000..999971a4
--- /dev/null
+++ b/core/src/main/scala/chisel3/internal/Namer.scala
@@ -0,0 +1,154 @@
+// See LICENSE for license details.
+
+// This file contains part of the implementation of the naming static annotation system.
+
+package chisel3.internal.naming
+import chisel3.experimental.NoChiselNamePrefix
+
+import scala.collection.mutable.Stack
+import scala.collection.mutable.ListBuffer
+
+import scala.collection.JavaConversions._
+
+import java.util.IdentityHashMap
+
+/** Recursive Function Namer overview
+ *
+ * In every function, creates a NamingContext object, which associates all vals with a string name
+ * suffix, for example:
+ * val myValName = SomeStatement()
+ * produces the entry in items:
+ * {ref of SomeStatement(), "myValName"}
+ *
+ * This is achieved with a macro transforming:
+ * val myValName = SomeStatement()
+ * statements into a naming call:
+ * val myValName = context.name(SomeStatement(), "myValName")
+ *
+ * The context is created from a global dynamic context stack at the beginning of each function.
+ * At the end of each function call, the completed context is added to its parent context and
+ * associated with the return value (whose name at an enclosing function call will form the prefix
+ * for all named objects).
+ *
+ * When the naming context prefix is given, it will name all of its items with the prefix and the
+ * associated suffix name. Then, it will check its descendants for sub-contexts with references
+ * matching the item reference, and if there is a match, it will (recursively) give the
+ * sub-context a prefix of its current prefix plus the item reference suffix.
+ *
+ * Note that for Modules, the macro will insert a naming context prefix call with an empty prefix,
+ * starting the recursive naming process.
+ */
+
+/** Base class for naming contexts, providing the basic API consisting of naming calls and
+ * ability to take descendant naming contexts.
+ */
+sealed trait NamingContextInterface {
+ /** Suggest a name (that will be propagated to FIRRTL) for an object, then returns the object
+ * itself (so this can be inserted transparently anywhere).
+ * Is a no-op (so safe) when applied on objects that aren't named, including non-Chisel data
+ * types.
+ */
+ def name[T](obj: T, name: String): T
+
+ /** Gives this context a naming prefix (which may be empty, "", for a top-level Module context)
+ * so that actual naming calls (HasId.suggestName) can happen.
+ * Recursively names descendants, for those whose return value have an associated name.
+ */
+ def namePrefix(prefix: String)
+}
+
+/** Dummy implementation to allow for naming annotations in a non-Builder context.
+ */
+object DummyNamer extends NamingContextInterface {
+ def name[T](obj: T, name: String): T = obj
+
+ def namePrefix(prefix: String): Unit = {
+ }
+}
+
+/** Actual namer functionality.
+ */
+class NamingContext extends NamingContextInterface {
+ val descendants = new IdentityHashMap[AnyRef, ListBuffer[NamingContext]]()
+ val anonymousDescendants = ListBuffer[NamingContext]()
+ val items = ListBuffer[(AnyRef, String)]()
+ var closed = false // a sanity check to ensure no more name() calls are done after name_prefix
+
+ /** Adds a NamingContext object as a descendant - where its contained objects will have names
+ * prefixed with the name given to the reference object, if the reference object is named in the
+ * scope of this context.
+ */
+ def addDescendant(ref: Any, descendant: NamingContext) {
+ ref match {
+ case ref: AnyRef =>
+ descendants.getOrElseUpdate(ref, ListBuffer[NamingContext]()) += descendant
+ case _ => anonymousDescendants += descendant
+ }
+ }
+
+ def name[T](obj: T, name: String): T = {
+ assert(!closed, "Can't name elements after name_prefix called")
+ obj match {
+ case _: NoChiselNamePrefix => // Don't name things with NoChiselNamePrefix
+ case ref: AnyRef => items += ((ref, name))
+ case _ =>
+ }
+ obj
+ }
+
+ def namePrefix(prefix: String): Unit = {
+ closed = true
+ for ((ref, suffix) <- items) {
+ // First name the top-level object
+ chisel3.internal.Builder.nameRecursively(prefix + suffix, ref, (id, name) => id.suggestName(name))
+
+ // Then recurse into descendant contexts
+ if (descendants.containsKey(ref)) {
+ for (descendant <- descendants.get(ref)) {
+ descendant.namePrefix(prefix + suffix + "_")
+ }
+ descendants.remove(ref)
+ }
+ }
+
+ for (descendant <- descendants.values().flatten) {
+ // Where we have a broken naming link, just ignore the missing parts
+ descendant.namePrefix(prefix)
+ }
+ for (descendant <- anonymousDescendants) {
+ descendant.namePrefix(prefix)
+ }
+ }
+}
+
+/** Class for the (global) naming stack object, which provides a way to push and pop naming
+ * contexts as functions are called / finished.
+ */
+class NamingStack {
+ val namingStack = Stack[NamingContext]()
+
+ /** Creates a new naming context, where all items in the context will have their names prefixed
+ * with some yet-to-be-determined prefix from object names in an enclosing scope.
+ */
+ def pushContext(): NamingContext = {
+ val context = new NamingContext
+ namingStack.push(context)
+ context
+ }
+
+ /** Called at the end of a function, popping the current naming context, adding it to the
+ * enclosing context's descendants, and passing through the prefix naming reference.
+ * Every instance of push_context() must have a matching pop_context().
+ *
+ * Will assert out if the context being popped isn't the topmost on the stack.
+ */
+ def popContext[T <: Any](prefixRef: T, until: NamingContext): Unit = {
+ assert(namingStack.top == until)
+ namingStack.pop()
+ if (!namingStack.isEmpty) {
+ namingStack.top.addDescendant(prefixRef, until)
+ }
+ }
+
+ def length() : Int = namingStack.length
+}
diff --git a/core/src/main/scala/chisel3/internal/SourceInfo.scala b/core/src/main/scala/chisel3/internal/SourceInfo.scala
new file mode 100644
index 00000000..f1130db4
--- /dev/null
+++ b/core/src/main/scala/chisel3/internal/SourceInfo.scala
@@ -0,0 +1,61 @@
+// 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 chisel3.internal.sourceinfo
+
+import scala.language.experimental.macros
+import scala.reflect.macros.blackbox.Context
+
+/** Abstract base class for generalized source information.
+ */
+sealed trait SourceInfo {
+ /** A prettier toString
+ *
+ * Make a useful message if SourceInfo is available, nothing otherwise
+ */
+ def makeMessage(f: String => String): String
+}
+
+sealed trait NoSourceInfo extends SourceInfo {
+ def makeMessage(f: String => String): String = ""
+}
+
+/** 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 {
+ def makeMessage(f: String => String): String = f(s"@[$filename $line:$col]")
+}
+
+/** 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_.chisel3.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/core/src/main/scala/chisel3/internal/firrtl/Converter.scala b/core/src/main/scala/chisel3/internal/firrtl/Converter.scala
new file mode 100644
index 00000000..5c1d6935
--- /dev/null
+++ b/core/src/main/scala/chisel3/internal/firrtl/Converter.scala
@@ -0,0 +1,275 @@
+// See LICENSE for license details.
+
+package chisel3.internal.firrtl
+import chisel3._
+import chisel3.experimental._
+import chisel3.internal.sourceinfo.{NoSourceInfo, SourceLine, SourceInfo}
+import firrtl.{ir => fir}
+import chisel3.internal.{castToInt, throwException}
+
+import scala.annotation.tailrec
+import scala.collection.immutable.Queue
+
+private[chisel3] object Converter {
+ // TODO modeled on unpack method on Printable, refactor?
+ def unpack(pable: Printable, ctx: Component): (String, Seq[Arg]) = pable match {
+ case Printables(pables) =>
+ val (fmts, args) = pables.map(p => unpack(p, ctx)).unzip
+ (fmts.mkString, args.flatten.toSeq)
+ case PString(str) => (str.replaceAll("%", "%%"), List.empty)
+ case format: FirrtlFormat =>
+ ("%" + format.specifier, List(format.bits.ref))
+ case Name(data) => (data.ref.name, List.empty)
+ case FullName(data) => (data.ref.fullName(ctx), List.empty)
+ case Percent => ("%%", List.empty)
+ }
+
+ def convert(info: SourceInfo): fir.Info = info match {
+ case _: NoSourceInfo => fir.NoInfo
+ case SourceLine(fn, line, col) => fir.FileInfo(fir.StringLit(s"$fn $line:$col"))
+ }
+
+ def convert(op: PrimOp): fir.PrimOp = firrtl.PrimOps.fromString(op.name)
+
+ def convert(dir: MemPortDirection): firrtl.MPortDir = dir match {
+ case MemPortDirection.INFER => firrtl.MInfer
+ case MemPortDirection.READ => firrtl.MRead
+ case MemPortDirection.WRITE => firrtl.MWrite
+ case MemPortDirection.RDWR => firrtl.MReadWrite
+ }
+
+ // TODO
+ // * Memoize?
+ // * Move into the Chisel IR?
+ def convert(arg: Arg, ctx: Component): fir.Expression = arg match { // scalastyle:ignore cyclomatic.complexity
+ case Node(id) =>
+ convert(id.getRef, ctx)
+ case Ref(name) =>
+ fir.Reference(name, fir.UnknownType)
+ case Slot(imm, name) =>
+ fir.SubField(convert(imm, ctx), name, fir.UnknownType)
+ case Index(imm, ILit(idx)) =>
+ fir.SubIndex(convert(imm, ctx), castToInt(idx, "Index"), fir.UnknownType)
+ case Index(imm, value) =>
+ fir.SubAccess(convert(imm, ctx), convert(value, ctx), fir.UnknownType)
+ case ModuleIO(mod, name) =>
+ // scalastyle:off if.brace
+ if (mod eq ctx.id) fir.Reference(name, fir.UnknownType)
+ else fir.SubField(fir.Reference(mod.getRef.name, fir.UnknownType), name, fir.UnknownType)
+ // scalastyle:on if.brace
+ case u @ ULit(n, UnknownWidth()) =>
+ fir.UIntLiteral(n, fir.IntWidth(u.minWidth))
+ case ULit(n, w) =>
+ fir.UIntLiteral(n, convert(w))
+ case slit @ SLit(n, w) => fir.SIntLiteral(n, convert(w))
+ val unsigned = if (n < 0) (BigInt(1) << slit.width.get) + n else n
+ val uint = convert(ULit(unsigned, slit.width), ctx)
+ fir.DoPrim(firrtl.PrimOps.AsSInt, Seq(uint), Seq.empty, fir.UnknownType)
+ // TODO Simplify
+ case fplit @ FPLit(n, w, bp) =>
+ val unsigned = if (n < 0) (BigInt(1) << fplit.width.get) + n else n
+ val uint = convert(ULit(unsigned, fplit.width), ctx)
+ val lit = bp.asInstanceOf[KnownBinaryPoint].value
+ fir.DoPrim(firrtl.PrimOps.AsFixedPoint, Seq(uint), Seq(lit), fir.UnknownType)
+ case intervalLit @ IntervalLit(n, w, bp) =>
+ val unsigned = if (n < 0) (BigInt(1) << intervalLit.width.get) + n else n
+ val uint = convert(ULit(unsigned, intervalLit.width), ctx)
+ val lit = bp.asInstanceOf[KnownBinaryPoint].value
+ fir.DoPrim(firrtl.PrimOps.AsInterval, Seq(uint), Seq(n, n, lit), fir.UnknownType)
+ case lit: ILit =>
+ throwException(s"Internal Error! Unexpected ILit: $lit")
+ }
+
+ /** Convert Commands that map 1:1 to Statements */
+ def convertSimpleCommand(cmd: Command, ctx: Component): Option[fir.Statement] = cmd match { // scalastyle:ignore cyclomatic.complexity line.size.limit
+ case e: DefPrim[_] =>
+ val consts = e.args.collect { case ILit(i) => i }
+ val args = e.args.flatMap {
+ case _: ILit => None
+ case other => Some(convert(other, ctx))
+ }
+ val expr = e.op.name match {
+ case "mux" =>
+ assert(args.size == 3, s"Mux with unexpected args: $args")
+ fir.Mux(args(0), args(1), args(2), fir.UnknownType)
+ case _ =>
+ fir.DoPrim(convert(e.op), args, consts, fir.UnknownType)
+ }
+ Some(fir.DefNode(convert(e.sourceInfo), e.name, expr))
+ case e @ DefWire(info, id) =>
+ Some(fir.DefWire(convert(info), e.name, extractType(id)))
+ case e @ DefReg(info, id, clock) =>
+ Some(fir.DefRegister(convert(info), e.name, extractType(id), convert(clock, ctx),
+ firrtl.Utils.zero, convert(id.getRef, ctx)))
+ case e @ DefRegInit(info, id, clock, reset, init) =>
+ Some(fir.DefRegister(convert(info), e.name, extractType(id), convert(clock, ctx),
+ convert(reset, ctx), convert(init, ctx)))
+ case e @ DefMemory(info, id, t, size) =>
+ Some(firrtl.CDefMemory(convert(info), e.name, extractType(t), size, false))
+ case e @ DefSeqMemory(info, id, t, size, ruw) =>
+ Some(firrtl.CDefMemory(convert(info), e.name, extractType(t), size, true, ruw))
+ case e: DefMemPort[_] =>
+ Some(firrtl.CDefMPort(convert(e.sourceInfo), e.name, fir.UnknownType,
+ e.source.fullName(ctx), Seq(convert(e.index, ctx), convert(e.clock, ctx)), convert(e.dir)))
+ case Connect(info, loc, exp) =>
+ Some(fir.Connect(convert(info), convert(loc, ctx), convert(exp, ctx)))
+ case BulkConnect(info, loc, exp) =>
+ Some(fir.PartialConnect(convert(info), convert(loc, ctx), convert(exp, ctx)))
+ case Attach(info, locs) =>
+ Some(fir.Attach(convert(info), locs.map(l => convert(l, ctx))))
+ case DefInvalid(info, arg) =>
+ Some(fir.IsInvalid(convert(info), convert(arg, ctx)))
+ case e @ DefInstance(info, id, _) =>
+ Some(fir.DefInstance(convert(info), e.name, id.name))
+ case Stop(info, clock, ret) =>
+ Some(fir.Stop(convert(info), ret, convert(clock, ctx), firrtl.Utils.one))
+ case Printf(info, clock, pable) =>
+ val (fmt, args) = unpack(pable, ctx)
+ Some(fir.Print(convert(info), fir.StringLit(fmt),
+ args.map(a => convert(a, ctx)), convert(clock, ctx), firrtl.Utils.one))
+ case _ => None
+ }
+
+ /** Internal datastructure to help translate Chisel's flat Command structure to FIRRTL's AST
+ *
+ * In particular, when scoping is translated from flat with begin end to a nested datastructure
+ *
+ * @param when Current when Statement, holds info, condition, and consequence as they are
+ * available
+ * @param outer Already converted Statements that precede the current when block in the scope in
+ * which the when is defined (ie. 1 level up from the scope inside the when)
+ * @param alt Indicates if currently processing commands in the alternate (else) of the when scope
+ */
+ // TODO we should probably have a different structure in the IR to close elses
+ private case class WhenFrame(when: fir.Conditionally, outer: Queue[fir.Statement], alt: Boolean)
+
+ /** Convert Chisel IR Commands into FIRRTL Statements
+ *
+ * @note ctx is needed because references to ports translate differently when referenced within
+ * the module in which they are defined vs. parent modules
+ * @param cmds Chisel IR Commands to convert
+ * @param ctx Component (Module) context within which we are translating
+ * @return FIRRTL Statement that is equivalent to the input cmds
+ */
+ def convert(cmds: Seq[Command], ctx: Component): fir.Statement = { // scalastyle:ignore cyclomatic.complexity
+ @tailrec
+ // scalastyle:off if.brace
+ def rec(acc: Queue[fir.Statement],
+ scope: List[WhenFrame])
+ (cmds: Seq[Command]): Seq[fir.Statement] = {
+ if (cmds.isEmpty) {
+ assert(scope.isEmpty)
+ acc
+ } else convertSimpleCommand(cmds.head, ctx) match {
+ // Most Commands map 1:1
+ case Some(stmt) =>
+ rec(acc :+ stmt, scope)(cmds.tail)
+ // When scoping logic does not map 1:1 and requires pushing/popping WhenFrames
+ // Please see WhenFrame for more details
+ case None => cmds.head match {
+ case WhenBegin(info, pred) =>
+ val when = fir.Conditionally(convert(info), convert(pred, ctx), fir.EmptyStmt, fir.EmptyStmt)
+ val frame = WhenFrame(when, acc, false)
+ rec(Queue.empty, frame +: scope)(cmds.tail)
+ case WhenEnd(info, depth, _) =>
+ val frame = scope.head
+ val when = if (frame.alt) frame.when.copy(alt = fir.Block(acc))
+ else frame.when.copy(conseq = fir.Block(acc))
+ // Check if this when has an else
+ cmds.tail.headOption match {
+ case Some(AltBegin(_)) =>
+ assert(!frame.alt, "Internal Error! Unexpected when structure!") // Only 1 else per when
+ rec(Queue.empty, frame.copy(when = when, alt = true) +: scope.tail)(cmds.drop(2))
+ case _ => // Not followed by otherwise
+ // If depth > 0 then we need to close multiple When scopes so we add a new WhenEnd
+ // If we're nested we need to add more WhenEnds to ensure each When scope gets
+ // properly closed
+ val cmdsx = if (depth > 0) WhenEnd(info, depth - 1, false) +: cmds.tail else cmds.tail
+ rec(frame.outer :+ when, scope.tail)(cmdsx)
+ }
+ case OtherwiseEnd(info, depth) =>
+ val frame = scope.head
+ val when = frame.when.copy(alt = fir.Block(acc))
+ // TODO For some reason depth == 1 indicates the last closing otherwise whereas
+ // depth == 0 indicates last closing when
+ val cmdsx = if (depth > 1) OtherwiseEnd(info, depth - 1) +: cmds.tail else cmds.tail
+ rec(scope.head.outer :+ when, scope.tail)(cmdsx)
+ }
+ }
+ }
+ // scalastyle:on if.brace
+ fir.Block(rec(Queue.empty, List.empty)(cmds))
+ }
+
+ def convert(width: Width): fir.Width = width match {
+ case UnknownWidth() => fir.UnknownWidth
+ case KnownWidth(value) => fir.IntWidth(value)
+ }
+
+ def convert(bp: BinaryPoint): fir.Width = bp match {
+ case UnknownBinaryPoint => fir.UnknownWidth
+ case KnownBinaryPoint(value) => fir.IntWidth(value)
+ }
+
+ private def firrtlUserDirOf(d: Data): SpecifiedDirection = d match {
+ case d: Vec[_] =>
+ SpecifiedDirection.fromParent(d.specifiedDirection, firrtlUserDirOf(d.sample_element))
+ case d => d.specifiedDirection
+ }
+
+ def extractType(data: Data, clearDir: Boolean = false): fir.Type = data match { // scalastyle:ignore cyclomatic.complexity line.size.limit
+ case _: Clock => fir.ClockType
+ case _: AsyncReset => fir.AsyncResetType
+ case _: ResetType => fir.ResetType
+ case d: EnumType => fir.UIntType(convert(d.width))
+ case d: UInt => fir.UIntType(convert(d.width))
+ case d: SInt => fir.SIntType(convert(d.width))
+ case d: FixedPoint => fir.FixedType(convert(d.width), convert(d.binaryPoint))
+ case d: Interval => fir.IntervalType(d.range.lowerBound, d.range.upperBound, d.range.firrtlBinaryPoint)
+ case d: Analog => fir.AnalogType(convert(d.width))
+ case d: Vec[_] => fir.VectorType(extractType(d.sample_element, clearDir), d.length)
+ case d: Record =>
+ val childClearDir = clearDir ||
+ d.specifiedDirection == SpecifiedDirection.Input || d.specifiedDirection == SpecifiedDirection.Output
+ def eltField(elt: Data): fir.Field = (childClearDir, firrtlUserDirOf(elt)) match {
+ case (true, _) => fir.Field(elt.getRef.name, fir.Default, extractType(elt, true))
+ case (false, SpecifiedDirection.Unspecified | SpecifiedDirection.Output) =>
+ fir.Field(elt.getRef.name, fir.Default, extractType(elt, false))
+ case (false, SpecifiedDirection.Flip | SpecifiedDirection.Input) =>
+ fir.Field(elt.getRef.name, fir.Flip, extractType(elt, false))
+ }
+ fir.BundleType(d.elements.toIndexedSeq.reverse.map { case (_, e) => eltField(e) })
+ }
+
+ def convert(name: String, param: Param): fir.Param = param match {
+ case IntParam(value) => fir.IntParam(name, value)
+ case DoubleParam(value) => fir.DoubleParam(name, value)
+ case StringParam(value) => fir.StringParam(name, fir.StringLit(value))
+ case RawParam(value) => fir.RawStringParam(name, value)
+ }
+ def convert(port: Port, topDir: SpecifiedDirection = SpecifiedDirection.Unspecified): fir.Port = {
+ val resolvedDir = SpecifiedDirection.fromParent(topDir, port.dir)
+ val dir = resolvedDir match {
+ case SpecifiedDirection.Unspecified | SpecifiedDirection.Output => fir.Output
+ case SpecifiedDirection.Flip | SpecifiedDirection.Input => fir.Input
+ }
+ val clearDir = resolvedDir match {
+ case SpecifiedDirection.Input | SpecifiedDirection.Output => true
+ case SpecifiedDirection.Unspecified | SpecifiedDirection.Flip => false
+ }
+ val tpe = extractType(port.id, clearDir)
+ fir.Port(fir.NoInfo, port.id.getRef.name, dir, tpe)
+ }
+
+ def convert(component: Component): fir.DefModule = component match {
+ case ctx @ DefModule(_, name, ports, cmds) =>
+ fir.Module(fir.NoInfo, name, ports.map(p => convert(p)), convert(cmds.toList, ctx))
+ case ctx @ DefBlackBox(id, name, ports, topDir, params) =>
+ fir.ExtModule(fir.NoInfo, name, ports.map(p => convert(p, topDir)), id.desiredName,
+ params.map { case (name, p) => convert(name, p) }.toSeq)
+ }
+
+ def convert(circuit: Circuit): fir.Circuit =
+ fir.Circuit(fir.NoInfo, circuit.components.map(convert), circuit.name)
+}
+
diff --git a/core/src/main/scala/chisel3/internal/firrtl/IR.scala b/core/src/main/scala/chisel3/internal/firrtl/IR.scala
new file mode 100644
index 00000000..d98bebcd
--- /dev/null
+++ b/core/src/main/scala/chisel3/internal/firrtl/IR.scala
@@ -0,0 +1,750 @@
+// See LICENSE for license details.
+
+package chisel3.internal.firrtl
+
+import firrtl.{ir => fir}
+
+import chisel3._
+import chisel3.internal._
+import chisel3.internal.sourceinfo.SourceInfo
+import chisel3.experimental._
+import _root_.firrtl.{ir => firrtlir}
+import _root_.firrtl.PrimOps
+
+import scala.collection.immutable.NumericRange
+import scala.math.BigDecimal.RoundingMode
+
+// scalastyle:off number.of.types
+
+case class PrimOp(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 AndReduceOp = PrimOp("andr")
+ val OrReduceOp = PrimOp("orr")
+ val XorReduceOp = PrimOp("xorr")
+ val ConvertOp = PrimOp("cvt")
+ val AsUIntOp = PrimOp("asUInt")
+ val AsSIntOp = PrimOp("asSInt")
+ val AsFixedPointOp = PrimOp("asFixedPoint")
+ val AsIntervalOp = PrimOp("asInterval")
+ val WrapOp = PrimOp("wrap")
+ val SqueezeOp = PrimOp("squz")
+ val ClipOp = PrimOp("clip")
+ val SetBinaryPoint = PrimOp("setp")
+ val IncreasePrecision = PrimOp("incp")
+ val DecreasePrecision = PrimOp("decp")
+ val AsClockOp = PrimOp("asClock")
+ val AsAsyncResetOp = PrimOp("asAsyncReset")
+}
+
+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.getOptionRef match {
+ case Some(arg) => arg.fullName(ctx)
+ case None => id.suggestedName.getOrElse("??")
+ }
+ def name: String = id.getOptionRef match {
+ case Some(arg) => arg.name
+ case None => id.suggestedName.getOrElse("??")
+ }
+}
+
+abstract class LitArg(val num: BigInt, widthArg: Width) extends Arg {
+ private[chisel3] def forcedWidth = widthArg.known
+ private[chisel3] def width: Width = if (forcedWidth) widthArg else Width(minWidth)
+ override def fullName(ctx: Component): String = name
+ // Ensure the node representing this LitArg has a ref to it and a literal binding.
+ def bindLitArg[T <: Element](elem: T): T = {
+ elem.bind(ElementLitBinding(this))
+ elem.setRef(this)
+ elem
+ }
+
+ protected def minWidth: Int
+ if (forcedWidth) {
+ require(widthArg.get >= minWidth,
+ s"The literal value ${num} was elaborated with a specified width of ${widthArg.get} bits, but at least ${minWidth} bits are required.") // scalastyle:ignore line.size.limit
+ }
+}
+
+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 FPLit(n: BigInt, w: Width, binaryPoint: BinaryPoint) extends LitArg(n, w) {
+ def name: String = {
+ val unsigned = if (n < 0) (BigInt(1) << width.get) + n else n
+ s"asFixedPoint(${ULit(unsigned, width).name}, ${binaryPoint.asInstanceOf[KnownBinaryPoint].value})"
+ }
+ def minWidth: Int = 1 + n.bitLength
+}
+
+case class IntervalLit(n: BigInt, w: Width, binaryPoint: BinaryPoint) extends LitArg(n, w) {
+ def name: String = {
+ val unsigned = if (n < 0) (BigInt(1) << width.get) + n else n
+ s"asInterval(${ULit(unsigned, width).name}, ${n}, ${n}, ${binaryPoint.asInstanceOf[KnownBinaryPoint].value})"
+ }
+ val range: IntervalRange = {
+ new IntervalRange(IntervalRange.getBound(isClosed = true, BigDecimal(n)),
+ IntervalRange.getBound(isClosed = true, BigDecimal(n)), IntervalRange.getRangeWidth(binaryPoint))
+ }
+ def minWidth: Int = 1 + n.bitLength
+}
+
+case class Ref(name: String) extends Arg
+case class ModuleIO(mod: BaseModule, 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}>"
+}
+
+object BinaryPoint {
+ def apply(x: Int): BinaryPoint = KnownBinaryPoint(x)
+ def apply(): BinaryPoint = UnknownBinaryPoint
+}
+
+sealed abstract class BinaryPoint {
+ type W = Int
+ def max(that: BinaryPoint): BinaryPoint = this.op(that, _ max _)
+ def + (that: BinaryPoint): BinaryPoint = this.op(that, _ + _)
+ def + (that: Int): BinaryPoint = this.op(this, (a, b) => a + that)
+ def shiftRight(that: Int): BinaryPoint = this.op(this, (a, b) => 0 max (a - that))
+ def dynamicShiftLeft(that: BinaryPoint): BinaryPoint =
+ this.op(that, (a, b) => a + (1 << b) - 1)
+
+ def known: Boolean
+ def get: W
+ protected def op(that: BinaryPoint, f: (W, W) => W): BinaryPoint
+}
+
+case object UnknownBinaryPoint extends BinaryPoint {
+ def known: Boolean = false
+ def get: Int = None.get
+ def op(that: BinaryPoint, f: (W, W) => W): BinaryPoint = this
+ override def toString: String = ""
+}
+
+sealed case class KnownBinaryPoint(value: Int) extends BinaryPoint {
+ def known: Boolean = true
+ def get: Int = value
+ def op(that: BinaryPoint, f: (W, W) => W): BinaryPoint = that match {
+ case KnownBinaryPoint(x) => KnownBinaryPoint(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")
+}
+
+sealed trait RangeType {
+ def getWidth: Width
+
+ def * (that: IntervalRange): IntervalRange
+ def +& (that: IntervalRange): IntervalRange
+ def -& (that: IntervalRange): IntervalRange
+ def << (that: Int): IntervalRange
+ def >> (that: Int): IntervalRange
+ def << (that: KnownWidth): IntervalRange
+ def >> (that: KnownWidth): IntervalRange
+ def merge(that: IntervalRange): IntervalRange
+}
+
+object IntervalRange {
+ /** Creates an IntervalRange, this is used primarily by the range interpolator macro
+ * @param lower lower bound
+ * @param upper upper bound
+ * @param firrtlBinaryPoint binary point firrtl style
+ * @return
+ */
+ def apply(lower: firrtlir.Bound, upper: firrtlir.Bound, firrtlBinaryPoint: firrtlir.Width): IntervalRange = {
+ new IntervalRange(lower, upper, firrtlBinaryPoint)
+ }
+
+ def apply(lower: firrtlir.Bound, upper: firrtlir.Bound, binaryPoint: BinaryPoint): IntervalRange = {
+ new IntervalRange(lower, upper, IntervalRange.getBinaryPoint(binaryPoint))
+ }
+
+ def apply(lower: firrtlir.Bound, upper: firrtlir.Bound, binaryPoint: Int): IntervalRange = {
+ IntervalRange(lower, upper, BinaryPoint(binaryPoint))
+ }
+
+ /** Returns an IntervalRange appropriate for a signed value of the given width
+ * @param binaryPoint number of bits of mantissa
+ * @return
+ */
+ def apply(binaryPoint: BinaryPoint): IntervalRange = {
+ IntervalRange(firrtlir.UnknownBound, firrtlir.UnknownBound, binaryPoint)
+ }
+
+ /** Returns an IntervalRange appropriate for a signed value of the given width
+ * @param width number of bits to have in the interval
+ * @param binaryPoint number of bits of mantissa
+ * @return
+ */
+ def apply(width: Width, binaryPoint: BinaryPoint = 0.BP): IntervalRange = {
+ val range = width match {
+ case KnownWidth(w) =>
+ val nearestPowerOf2 = BigInt("1" + ("0" * (w - 1)), 2)
+ IntervalRange(
+ firrtlir.Closed(BigDecimal(-nearestPowerOf2)), firrtlir.Closed(BigDecimal(nearestPowerOf2 - 1)), binaryPoint
+ )
+ case _ =>
+ IntervalRange(firrtlir.UnknownBound, firrtlir.UnknownBound, binaryPoint)
+ }
+ range
+ }
+
+ def unapply(arg: IntervalRange): Option[(firrtlir.Bound, firrtlir.Bound, BinaryPoint)] = {
+ return Some((arg.lower, arg.upper, arg.binaryPoint))
+ }
+
+ def getBound(isClosed: Boolean, value: String): firrtlir.Bound = {
+ if(value == "?") {
+ firrtlir.UnknownBound
+ }
+ else if(isClosed) {
+ firrtlir.Closed(BigDecimal(value))
+ }
+ else {
+ firrtlir.Open(BigDecimal(value))
+ }
+ }
+
+ def getBound(isClosed: Boolean, value: BigDecimal): firrtlir.Bound = {
+ if(isClosed) {
+ firrtlir.Closed(value)
+ }
+ else {
+ firrtlir.Open(value)
+ }
+ }
+
+ def getBound(isClosed: Boolean, value: Int): firrtlir.Bound = {
+ getBound(isClosed, (BigDecimal(value)))
+ }
+
+ def getBinaryPoint(s: String): firrtlir.Width = {
+ firrtlir.UnknownWidth
+ }
+
+ def getBinaryPoint(n: Int): firrtlir.Width = {
+ if(n < 0) {
+ firrtlir.UnknownWidth
+ }
+ else {
+ firrtlir.IntWidth(n)
+ }
+ }
+ def getBinaryPoint(n: BinaryPoint): firrtlir.Width = {
+ n match {
+ case UnknownBinaryPoint => firrtlir.UnknownWidth
+ case KnownBinaryPoint(w) => firrtlir.IntWidth(w)
+ }
+ }
+
+ def getRangeWidth(w: Width): firrtlir.Width = {
+ if(w.known) {
+ firrtlir.IntWidth(w.get)
+ }
+ else {
+ firrtlir.UnknownWidth
+ }
+ }
+ def getRangeWidth(binaryPoint: BinaryPoint): firrtlir.Width = {
+ if(binaryPoint.known) {
+ firrtlir.IntWidth(binaryPoint.get)
+ }
+ else {
+ firrtlir.UnknownWidth
+ }
+ }
+
+ //scalastyle:off method.name
+ def Unknown: IntervalRange = range"[?,?].?"
+}
+
+
+sealed class IntervalRange(
+ val lowerBound: firrtlir.Bound,
+ val upperBound: firrtlir.Bound,
+ private[chisel3] val firrtlBinaryPoint: firrtlir.Width)
+ extends firrtlir.IntervalType(lowerBound, upperBound, firrtlBinaryPoint)
+ with RangeType {
+
+ (lowerBound, upperBound) match {
+ case (firrtlir.Open(begin), firrtlir.Open(end)) =>
+ if(begin >= end) throw new ChiselException(s"Invalid range with ${serialize}")
+ binaryPoint match {
+ case KnownBinaryPoint(bp) =>
+ if(begin >= end - (BigDecimal(1) / BigDecimal(BigInt(1) << bp))) {
+ throw new ChiselException(s"Invalid range with ${serialize}")
+ }
+ case _ =>
+ }
+ case (firrtlir.Open(begin), firrtlir.Closed(end)) =>
+ if(begin >= end) throw new ChiselException(s"Invalid range with ${serialize}")
+ case (firrtlir.Closed(begin), firrtlir.Open(end)) =>
+ if(begin >= end) throw new ChiselException(s"Invalid range with ${serialize}")
+ case (firrtlir.Closed(begin), firrtlir.Closed(end)) =>
+ if(begin > end) throw new ChiselException(s"Invalid range with ${serialize}")
+ case _ =>
+ }
+
+ //scalastyle:off cyclomatic.complexity
+ override def toString: String = {
+ val binaryPoint = firrtlBinaryPoint match {
+ case firrtlir.IntWidth(n) => s"$n"
+ case _ => "?"
+ }
+ val lowerBoundString = lowerBound match {
+ case firrtlir.Closed(l) => s"[$l"
+ case firrtlir.Open(l) => s"($l"
+ case firrtlir.UnknownBound => s"[?"
+ }
+ val upperBoundString = upperBound match {
+ case firrtlir.Closed(l) => s"$l]"
+ case firrtlir.Open(l) => s"$l)"
+ case firrtlir.UnknownBound => s"?]"
+ }
+ s"""range"$lowerBoundString,$upperBoundString.$binaryPoint""""
+ }
+
+ val increment: Option[BigDecimal] = firrtlBinaryPoint match {
+ case firrtlir.IntWidth(bp) =>
+ Some(BigDecimal(math.pow(2, -bp.doubleValue)))
+ case _ => None
+ }
+
+ /** If possible returns the lowest possible value for this Interval
+ * @return
+ */
+ val getLowestPossibleValue: Option[BigDecimal] = {
+ increment match {
+ case Some(inc) =>
+ lower match {
+ case firrtlir.Closed(n) => Some(n)
+ case firrtlir.Open(n) => Some(n + inc)
+ case _ => None
+ }
+ case _ =>
+ None
+ }
+ }
+
+ /** If possible returns the highest possible value for this Interval
+ * @return
+ */
+ val getHighestPossibleValue: Option[BigDecimal] = {
+ increment match {
+ case Some(inc) =>
+ upper match {
+ case firrtlir.Closed(n) => Some(n)
+ case firrtlir.Open(n) => Some(n - inc)
+ case _ => None
+ }
+ case _ =>
+ None
+ }
+ }
+
+ /** Return a Seq of the possible values for this range
+ * Mostly to be used for testing
+ * @return
+ */
+ def getPossibleValues: NumericRange[BigDecimal] = {
+ (getLowestPossibleValue, getHighestPossibleValue, increment) match {
+ case (Some(low), Some(high), Some(inc)) => (low to high by inc)
+ case (_, _, None) =>
+ throw new ChiselException(s"BinaryPoint unknown. Cannot get possible values from IntervalRange $toString")
+ case _ =>
+ throw new ChiselException(s"Unknown Bound. Cannot get possible values from IntervalRange $toString")
+
+ }
+ }
+
+ override def getWidth: Width = {
+ width match {
+ case firrtlir.IntWidth(n) => KnownWidth(n.toInt)
+ case firrtlir.UnknownWidth => UnknownWidth()
+ }
+ }
+
+ private def doFirrtlOp(op: firrtlir.PrimOp, that: IntervalRange): IntervalRange = {
+ PrimOps.set_primop_type(
+ firrtlir.DoPrim(op,
+ Seq(firrtlir.Reference("a", this), firrtlir.Reference("b", that)), Nil,firrtlir.UnknownType)
+ ).tpe match {
+ case i: firrtlir.IntervalType => IntervalRange(i.lower, i.upper, i.point)
+ case other => sys.error("BAD!")
+ }
+ }
+
+ private def doFirrtlDynamicShift(that: UInt, isLeft: Boolean): IntervalRange = {
+ val uinttpe = that.widthOption match {
+ case None => firrtlir.UIntType(firrtlir.UnknownWidth)
+ case Some(w) => firrtlir.UIntType(firrtlir.IntWidth(w))
+ }
+ val op = if(isLeft) PrimOps.Dshl else PrimOps.Dshr
+ PrimOps.set_primop_type(
+ firrtlir.DoPrim(op,
+ Seq(firrtlir.Reference("a", this), firrtlir.Reference("b", uinttpe)), Nil,firrtlir.UnknownType)
+ ).tpe match {
+ case i: firrtlir.IntervalType => IntervalRange(i.lower, i.upper, i.point)
+ case other => sys.error("BAD!")
+ }
+ }
+
+ private def doFirrtlOp(op: firrtlir.PrimOp, that: Int): IntervalRange = {
+ PrimOps.set_primop_type(
+ firrtlir.DoPrim(op,
+ Seq(firrtlir.Reference("a", this)), Seq(BigInt(that)), firrtlir.UnknownType)
+ ).tpe match {
+ case i: firrtlir.IntervalType => IntervalRange(i.lower, i.upper, i.point)
+ case other => sys.error("BAD!")
+ }
+ }
+
+ /** Multiply this by that, here we return a fully unknown range,
+ * firrtl's range inference can figure this out
+ * @param that
+ * @return
+ */
+ override def *(that: IntervalRange): IntervalRange = {
+ doFirrtlOp(PrimOps.Mul, that)
+ }
+
+ /** Add that to this, here we return a fully unknown range,
+ * firrtl's range inference can figure this out
+ * @param that
+ * @return
+ */
+ override def +&(that: IntervalRange): IntervalRange = {
+ doFirrtlOp(PrimOps.Add, that)
+ }
+
+ /** Subtract that from this, here we return a fully unknown range,
+ * firrtl's range inference can figure this out
+ * @param that
+ * @return
+ */
+ override def -&(that: IntervalRange): IntervalRange = {
+ doFirrtlOp(PrimOps.Sub, that)
+ }
+
+ private def adjustBoundValue(value: BigDecimal, binaryPointValue: Int): BigDecimal = {
+ if(binaryPointValue >= 0) {
+ val maskFactor = BigDecimal(1 << binaryPointValue)
+ val a = (value * maskFactor)
+ val b = a.setScale(0, RoundingMode.DOWN)
+ val c = b / maskFactor
+ c
+ } else {
+ value
+ }
+ }
+
+ private def adjustBound(bound: firrtlir.Bound, binaryPoint: BinaryPoint): firrtlir.Bound = {
+ binaryPoint match {
+ case KnownBinaryPoint(binaryPointValue) =>
+ bound match {
+ case firrtlir.Open(value) => firrtlir.Open(adjustBoundValue(value, binaryPointValue))
+ case firrtlir.Closed(value) => firrtlir.Closed(adjustBoundValue(value, binaryPointValue))
+ case _ => bound
+ }
+ case _ => firrtlir.UnknownBound
+ }
+ }
+
+ /** Creates a new range with the increased precision
+ *
+ * @param newBinaryPoint
+ * @return
+ */
+ def incPrecision(newBinaryPoint: BinaryPoint): IntervalRange = {
+ newBinaryPoint match {
+ case KnownBinaryPoint(that) =>
+ doFirrtlOp(PrimOps.IncP, that)
+ case _ =>
+ throwException(s"$this.incPrecision(newBinaryPoint = $newBinaryPoint) error, newBinaryPoint must be know")
+ }
+ }
+
+ /** Creates a new range with the decreased precision
+ *
+ * @param newBinaryPoint
+ * @return
+ */
+ def decPrecision(newBinaryPoint: BinaryPoint): IntervalRange = {
+ newBinaryPoint match {
+ case KnownBinaryPoint(that) =>
+ doFirrtlOp(PrimOps.DecP, that)
+ case _ =>
+ throwException(s"$this.decPrecision(newBinaryPoint = $newBinaryPoint) error, newBinaryPoint must be know")
+ }
+ }
+
+ /** Creates a new range with the given binary point, adjusting precision
+ * on bounds as necessary
+ *
+ * @param newBinaryPoint
+ * @return
+ */
+ def setPrecision(newBinaryPoint: BinaryPoint): IntervalRange = {
+ newBinaryPoint match {
+ case KnownBinaryPoint(that) =>
+ doFirrtlOp(PrimOps.SetP, that)
+ case _ =>
+ throwException(s"$this.setPrecision(newBinaryPoint = $newBinaryPoint) error, newBinaryPoint must be know")
+ }
+ }
+
+ /** Shift this range left, i.e. shifts the min and max by the specified amount
+ * @param that
+ * @return
+ */
+ override def <<(that: Int): IntervalRange = {
+ doFirrtlOp(PrimOps.Shl, that)
+ }
+
+ /** Shift this range left, i.e. shifts the min and max by the known width
+ * @param that
+ * @return
+ */
+ override def <<(that: KnownWidth): IntervalRange = {
+ <<(that.value)
+ }
+
+ /** Shift this range left, i.e. shifts the min and max by value
+ * @param that
+ * @return
+ */
+ def <<(that: UInt): IntervalRange = {
+ doFirrtlDynamicShift(that, isLeft = true)
+ }
+
+ /** Shift this range right, i.e. shifts the min and max by the specified amount
+ * @param that
+ * @return
+ */
+ override def >>(that: Int): IntervalRange = {
+ doFirrtlOp(PrimOps.Shr, that)
+ }
+
+ /** Shift this range right, i.e. shifts the min and max by the known width
+ * @param that
+ * @return
+ */
+ override def >>(that: KnownWidth): IntervalRange = {
+ >>(that.value)
+ }
+
+ /** Shift this range right, i.e. shifts the min and max by value
+ * @param that
+ * @return
+ */
+ def >>(that: UInt): IntervalRange = {
+ doFirrtlDynamicShift(that, isLeft = false)
+ }
+
+ /**
+ * Squeeze returns the intersection of the ranges this interval and that Interval
+ * @param that
+ * @return
+ */
+ def squeeze(that: IntervalRange): IntervalRange = {
+ doFirrtlOp(PrimOps.Squeeze, that)
+ }
+
+ /**
+ * Wrap the value of this [[Interval]] into the range of a different Interval with a presumably smaller range.
+ * @param that
+ * @return
+ */
+ def wrap(that: IntervalRange): IntervalRange = {
+ doFirrtlOp(PrimOps.Wrap, that)
+ }
+
+ /**
+ * Clip the value of this [[Interval]] into the range of a different Interval with a presumably smaller range.
+ * @param that
+ * @return
+ */
+ def clip(that: IntervalRange): IntervalRange = {
+ doFirrtlOp(PrimOps.Clip, that)
+ }
+
+ /** merges the ranges of this and that, basically takes lowest low, highest high and biggest bp
+ * set unknown if any of this or that's value of above is unknown
+ * Like an union but will slurp up points in between the two ranges that were part of neither
+ * @param that
+ * @return
+ */
+ override def merge(that: IntervalRange): IntervalRange = {
+ val lowest = (this.getLowestPossibleValue, that.getLowestPossibleValue) match {
+ case (Some(l1), Some(l2)) =>
+ if(l1 < l2) { this.lower } else { that.lower }
+ case _ =>
+ firrtlir.UnknownBound
+ }
+ val highest = (this.getHighestPossibleValue, that.getHighestPossibleValue) match {
+ case (Some(l1), Some(l2)) =>
+ if(l1 >= l2) { this.lower } else { that.lower }
+ case _ =>
+ firrtlir.UnknownBound
+ }
+ val newBinaryPoint = (this.firrtlBinaryPoint, that.firrtlBinaryPoint) match {
+ case (firrtlir.IntWidth(b1), firrtlir.IntWidth(b2)) =>
+ if(b1 > b2) { firrtlir.IntWidth(b1)} else { firrtlir.IntWidth(b2) }
+ case _ =>
+ firrtlir.UnknownWidth
+ }
+ IntervalRange(lowest, highest, newBinaryPoint)
+ }
+
+ def binaryPoint: BinaryPoint = {
+ firrtlBinaryPoint match {
+ case firrtlir.IntWidth(n) =>
+ assert(n < Int.MaxValue, s"binary point value $n is out of range")
+ KnownBinaryPoint(n.toInt)
+ case _ => UnknownBinaryPoint
+ }
+ }
+}
+
+abstract class Command {
+ def sourceInfo: SourceInfo
+}
+abstract class Definition extends Command {
+ def id: HasId
+ def name: String = id.getRef.name
+}
+// scalastyle:off line.size.limit
+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: BigInt) extends Definition
+case class DefSeqMemory(sourceInfo: SourceInfo, id: HasId, t: Data, size: BigInt, readUnderWrite: fir.ReadUnderWrite.Value) 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: BaseModule, ports: Seq[Port]) extends Definition
+case class WhenBegin(sourceInfo: SourceInfo, pred: Arg) extends Command
+case class WhenEnd(sourceInfo: SourceInfo, firrtlDepth: Int, hasAlt: Boolean = false) extends Command
+case class AltBegin(sourceInfo: SourceInfo) extends Command
+case class OtherwiseEnd(sourceInfo: SourceInfo, firrtlDepth: Int) 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 Attach(sourceInfo: SourceInfo, locs: Seq[Node]) extends Command
+case class ConnectInit(sourceInfo: SourceInfo, loc: Node, exp: Arg) extends Command
+case class Stop(sourceInfo: SourceInfo, clock: Arg, ret: Int) extends Command
+case class Port(id: Data, dir: SpecifiedDirection)
+case class Printf(sourceInfo: SourceInfo, clock: Arg, pable: Printable) extends Command
+abstract class Component extends Arg {
+ def id: BaseModule
+ def name: String
+ def ports: Seq[Port]
+}
+case class DefModule(id: RawModule, name: String, ports: Seq[Port], commands: Seq[Command]) extends Component
+case class DefBlackBox(id: BaseBlackBox, name: String, ports: Seq[Port], topDir: SpecifiedDirection, params: Map[String, Param]) extends Component
+
+case class Circuit(name: String, components: Seq[Component], annotations: Seq[ChiselAnnotation] = Seq.empty)
diff --git a/core/src/main/scala/chisel3/package.scala b/core/src/main/scala/chisel3/package.scala
new file mode 100644
index 00000000..65bfdeb7
--- /dev/null
+++ b/core/src/main/scala/chisel3/package.scala
@@ -0,0 +1,229 @@
+// See LICENSE for license details.
+
+import chisel3.internal.firrtl.BinaryPoint
+
+/** This package contains the main chisel3 API.
+ */
+package object chisel3 { // scalastyle:ignore package.object.name
+ import internal.firrtl.{Port, Width}
+ import internal.Builder
+
+ import scala.language.implicitConversions
+
+ /**
+ * These implicit classes allow one to convert scala.Int|scala.BigInt to
+ * Chisel.UInt|Chisel.SInt by calling .asUInt|.asSInt on them, respectively.
+ * The versions .asUInt(width)|.asSInt(width) are also available to explicitly
+ * mark a width for the new literal.
+ *
+ * Also provides .asBool to scala.Boolean and .asUInt to String
+ *
+ * Note that, for stylistic reasons, one should avoid extracting immediately
+ * after this call using apply, ie. 0.asUInt(1)(0) due to potential for
+ * confusion (the 1 is a bit length and the 0 is a bit extraction position).
+ * Prefer storing the result and then extracting from it.
+ *
+ * Implementation note: the empty parameter list (like `U()`) is necessary to prevent
+ * interpreting calls that have a non-Width parameter as a chained apply, otherwise things like
+ * `0.asUInt(16)` (instead of `16.W`) compile without error and produce undesired results.
+ */
+ implicit class fromBigIntToLiteral(bigint: BigInt) {
+ /** Int to Bool conversion, allowing compact syntax like 1.B and 0.B
+ */
+ def B: Bool = bigint match { // scalastyle:ignore method.name
+ case bigint if bigint == 0 => Bool.Lit(false)
+ case bigint if bigint == 1 => Bool.Lit(true)
+ case bigint => Builder.error(s"Cannot convert $bigint to Bool, must be 0 or 1"); Bool.Lit(false)
+ }
+ /** Int to UInt conversion, recommended style for constants.
+ */
+ def U: UInt = UInt.Lit(bigint, Width()) // scalastyle:ignore method.name
+ /** Int to SInt conversion, recommended style for constants.
+ */
+ def S: SInt = SInt.Lit(bigint, Width()) // scalastyle:ignore method.name
+ /** Int to UInt conversion with specified width, recommended style for constants.
+ */
+ def U(width: Width): UInt = UInt.Lit(bigint, width) // scalastyle:ignore method.name
+ /** Int to SInt conversion with specified width, recommended style for constants.
+ */
+ def S(width: Width): SInt = SInt.Lit(bigint, width) // scalastyle:ignore method.name
+
+ /** Int to UInt conversion, recommended style for variables.
+ */
+ def asUInt(): UInt = UInt.Lit(bigint, Width())
+ /** Int to SInt conversion, recommended style for variables.
+ */
+ def asSInt(): SInt = SInt.Lit(bigint, Width())
+ /** Int to UInt conversion with specified width, recommended style for variables.
+ */
+ def asUInt(width: Width): UInt = UInt.Lit(bigint, width)
+ /** Int to SInt conversion with specified width, recommended style for variables.
+ */
+ def asSInt(width: Width): SInt = SInt.Lit(bigint, width)
+ }
+
+ implicit class fromIntToLiteral(int: Int) extends fromBigIntToLiteral(int)
+ implicit class fromLongToLiteral(long: Long) extends fromBigIntToLiteral(long)
+
+ implicit class fromStringToLiteral(str: String) {
+ /** String to UInt parse, recommended style for constants.
+ */
+ def U: UInt = str.asUInt() // scalastyle:ignore method.name
+ /** String to UInt parse with specified width, recommended style for constants.
+ */
+ def U(width: Width): UInt = str.asUInt(width) // scalastyle:ignore method.name
+
+ /** String to UInt parse, recommended style for variables.
+ */
+ def asUInt(): UInt = {
+ val bigInt = parse(str)
+ UInt.Lit(bigInt, Width(bigInt.bitLength max 1))
+ }
+ /** String to UInt parse with specified width, recommended style for variables.
+ */
+ def asUInt(width: Width): UInt = UInt.Lit(parse(str), width)
+
+ protected def parse(n: String): BigInt = {
+ 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)
+ }
+ }
+
+ implicit class fromIntToBinaryPoint(int: Int) {
+ def BP: BinaryPoint = BinaryPoint(int) // scalastyle:ignore method.name
+ }
+
+ implicit class fromBooleanToLiteral(boolean: Boolean) {
+ /** Boolean to Bool conversion, recommended style for constants.
+ */
+ def B: Bool = Bool.Lit(boolean) // scalastyle:ignore method.name
+
+ /** Boolean to Bool conversion, recommended style for variables.
+ */
+ def asBool(): Bool = Bool.Lit(boolean)
+ }
+
+ // Fixed Point is experimental for now, but we alias the implicit conversion classes here
+ // to minimize disruption with existing code.
+ implicit class fromDoubleToLiteral(double: Double)
+ extends experimental.FixedPoint.Implicits.fromDoubleToLiteral(double)
+
+ implicit class fromBigDecimalToLiteral(bigDecimal: BigDecimal)
+ extends experimental.FixedPoint.Implicits.fromBigDecimalToLiteral(bigDecimal)
+
+ // Interval is experimental for now, but we alias the implicit conversion classes here
+ // to minimize disruption with existing code.
+ implicit class fromIntToLiteralInterval(int: Int)
+ extends experimental.Interval.Implicits.fromIntToLiteralInterval(int)
+
+ implicit class fromLongToLiteralInterval(long: Long)
+ extends experimental.Interval.Implicits.fromLongToLiteralInterval(long)
+
+ implicit class fromBigIntToLiteralInterval(bigInt: BigInt)
+ extends experimental.Interval.Implicits.fromBigIntToLiteralInterval(bigInt)
+
+ implicit class fromDoubleToLiteralInterval(double: Double)
+ extends experimental.Interval.Implicits.fromDoubleToLiteralInterval(double)
+
+ implicit class fromBigDecimalToLiteralInterval(bigDecimal: BigDecimal)
+ extends experimental.Interval.Implicits.fromBigDecimalToLiteralInterval(bigDecimal)
+
+ implicit class fromIntToWidth(int: Int) {
+ def W: Width = Width(int) // scalastyle:ignore method.name
+ }
+
+ val WireInit = WireDefault
+
+ object Vec extends VecFactory
+
+ // Some possible regex replacements for the literal specifier deprecation:
+ // (note: these are not guaranteed to handle all edge cases! check all replacements!)
+ // Bool\((true|false)\)
+ // => $1.B
+ // UInt\(width\s*=\s*(\d+|[_a-zA-Z][_0-9a-zA-Z]*)\)
+ // => UInt($1.W)
+ // (UInt|SInt|Bits).width\((\d+|[_a-zA-Z][_0-9a-zA-Z]*)\)
+ // => $1($2.W)
+ // (U|S)Int\((-?\d+|0[xX][0-9a-fA-F]+)\)
+ // => $2.$1
+ // UInt\((\d+|0[xX][0-9a-fA-F]+),\s*(?:width\s*=)?\s*(\d+|[_a-zA-Z][_0-9a-zA-Z]*)\)
+ // => $1.U($2.W)
+ // (UInt|SInt|Bool)\(([_a-zA-Z][_0-9a-zA-Z]*)\)
+ // => $2.as$1
+ // (UInt|SInt)\(([_a-zA-Z][_0-9a-zA-Z]*),\s*(?:width\s*=)?\s*(\d+|[_a-zA-Z][_0-9a-zA-Z]*)\)
+ // => $2.as$1($3.W)
+
+ object Bits extends UIntFactory
+ object UInt extends UIntFactory
+ object SInt extends SIntFactory
+ object Bool extends BoolFactory
+
+ type InstanceId = internal.InstanceId
+
+ type Module = chisel3.internal.LegacyModule
+
+ /** Implicit for custom Printable string interpolator */
+ implicit class PrintableHelper(val sc: StringContext) extends AnyVal {
+ /** Custom string interpolator for generating Printables: p"..."
+ * Will call .toString on any non-Printable arguments (mimicking s"...")
+ */
+ def p(args: Any*): Printable = {
+ sc.checkLengths(args) // Enforce sc.parts.size == pargs.size + 1
+ val pargs: Seq[Option[Printable]] = args map {
+ case p: Printable => Some(p)
+ case d: Data => Some(d.toPrintable)
+ case any => for {
+ v <- Option(any) // Handle null inputs
+ str = v.toString
+ if !str.isEmpty // Handle empty Strings
+ } yield PString(str)
+ }
+ val parts = sc.parts map StringContext.treatEscapes
+ // Zip sc.parts and pargs together ito flat Seq
+ // eg. Seq(sc.parts(0), pargs(0), sc.parts(1), pargs(1), ...)
+ val seq = for { // append None because sc.parts.size == pargs.size + 1
+ (literal, arg) <- parts zip (pargs :+ None)
+ optPable <- Seq(Some(PString(literal)), arg)
+ pable <- optPable // Remove Option[_]
+ } yield pable
+ Printables(seq)
+ }
+ }
+
+ implicit def string2Printable(str: String): Printable = PString(str)
+
+ type ChiselException = internal.ChiselException
+
+ // Debugger/Tester access to internal Chisel data structures and methods.
+ def getDataElements(a: Aggregate): Seq[Element] = {
+ a.allElements
+ }
+ def getModulePorts(m: Module): Seq[Port] = m.getPorts
+ // Invalidate API - a DontCare element for explicit assignment to outputs,
+ // indicating the signal is intentionally not driven.
+ val DontCare = chisel3.internal.InternalDontCare
+
+ class BindingException(message: String) extends ChiselException(message)
+ /** A function expected a Chisel type but got a hardware object
+ */
+ case class ExpectedChiselTypeException(message: String) extends BindingException(message)
+ /**A function expected a hardware object but got a Chisel type
+ */
+ case class ExpectedHardwareException(message: String) extends BindingException(message)
+ /** An aggregate had a mix of specified and unspecified directionality children
+ */
+ case class MixedDirectionAggregateException(message: String) extends BindingException(message)
+ /** Attempted to re-bind an already bound (directionality or hardware) object
+ */
+ case class RebindingException(message: String) extends BindingException(message)
+ // Connection exceptions.
+ case class BiConnectException(message: String) extends ChiselException(message)
+ case class MonoConnectException(message: String) extends ChiselException(message)
+}