From 878d488a7c8e0d6973de58b3164022c6a102e449 Mon Sep 17 00:00:00 2001 From: Aditya Naik Date: Fri, 3 May 2024 10:59:45 -0700 Subject: Get cleanup to compile --- .../main/scala/chisel3/experimental/Analog.scala | 3 +- .../main/scala/chisel3/experimental/Attach.scala | 2 +- .../experimental/dataview/DataProduct.scala | 326 ----------- .../chisel3/experimental/dataview/DataView.scala | 618 --------------------- .../chisel3/experimental/dataview/package.scala | 268 --------- .../experimental/hierarchy/Definition.scala | 126 ----- .../chisel3/experimental/hierarchy/Hierarchy.scala | 117 ---- .../chisel3/experimental/hierarchy/Instance.scala | 148 ----- .../experimental/hierarchy/IsInstantiable.scala | 16 - .../experimental/hierarchy/IsLookupable.scala | 25 - .../experimental/hierarchy/LibraryHooks.scala | 34 -- .../experimental/hierarchy/Lookupable.scala | 511 ----------------- .../experimental/hierarchy/Underlying.scala | 14 - .../chisel3/experimental/hierarchy/package.scala | 48 -- .../main/scala/chisel3/experimental/package.scala | 75 --- 15 files changed, 2 insertions(+), 2329 deletions(-) delete mode 100644 core/src/main/scala/chisel3/experimental/dataview/DataProduct.scala delete mode 100644 core/src/main/scala/chisel3/experimental/dataview/DataView.scala delete mode 100644 core/src/main/scala/chisel3/experimental/dataview/package.scala delete mode 100644 core/src/main/scala/chisel3/experimental/hierarchy/Definition.scala delete mode 100644 core/src/main/scala/chisel3/experimental/hierarchy/Hierarchy.scala delete mode 100644 core/src/main/scala/chisel3/experimental/hierarchy/Instance.scala delete mode 100644 core/src/main/scala/chisel3/experimental/hierarchy/IsInstantiable.scala delete mode 100644 core/src/main/scala/chisel3/experimental/hierarchy/IsLookupable.scala delete mode 100644 core/src/main/scala/chisel3/experimental/hierarchy/LibraryHooks.scala delete mode 100644 core/src/main/scala/chisel3/experimental/hierarchy/Lookupable.scala delete mode 100644 core/src/main/scala/chisel3/experimental/hierarchy/Underlying.scala delete mode 100644 core/src/main/scala/chisel3/experimental/hierarchy/package.scala (limited to 'core/src/main/scala/chisel3/experimental') diff --git a/core/src/main/scala/chisel3/experimental/Analog.scala b/core/src/main/scala/chisel3/experimental/Analog.scala index 7d89025c..7bb0ac5d 100644 --- a/core/src/main/scala/chisel3/experimental/Analog.scala +++ b/core/src/main/scala/chisel3/experimental/Analog.scala @@ -13,7 +13,6 @@ import chisel3.{ Element, PString, Printable, - RawModule, SpecifiedDirection, UInt } @@ -50,7 +49,7 @@ final class Analog private (private[chisel3] val width: Width) extends Element { // 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] + private[chisel3] val biConnectLocs = mutable.Map.empty[BaseModule, SourceInfo] // Define setter/getter pairing // Analog can only be bound to Ports and Wires (and Unbound) diff --git a/core/src/main/scala/chisel3/experimental/Attach.scala b/core/src/main/scala/chisel3/experimental/Attach.scala index 5c9cfe53..1d32e941 100644 --- a/core/src/main/scala/chisel3/experimental/Attach.scala +++ b/core/src/main/scala/chisel3/experimental/Attach.scala @@ -15,7 +15,7 @@ object attach { AttachException(": Conditional attach is not allowed!") // Actual implementation - private[chisel3] def impl(elts: Seq[Analog], contextModule: RawModule)(implicit sourceInfo: SourceInfo): Unit = { + private[chisel3] def impl(elts: Seq[Analog], contextModule: BaseModule)(implicit sourceInfo: SourceInfo): Unit = { if (Builder.whenDepth != 0) throw ConditionalAttachException // TODO Check that references are valid and can be attached diff --git a/core/src/main/scala/chisel3/experimental/dataview/DataProduct.scala b/core/src/main/scala/chisel3/experimental/dataview/DataProduct.scala deleted file mode 100644 index c6ebe604..00000000 --- a/core/src/main/scala/chisel3/experimental/dataview/DataProduct.scala +++ /dev/null @@ -1,326 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 - -package chisel3.experimental.dataview - -import chisel3.experimental.BaseModule -import chisel3.{getRecursiveFields, Data, Vec} - -import scala.annotation.implicitNotFound - -/** Typeclass interface for getting elements of type [[Data]] - * - * This is needed for validating [[DataView]]s targeting type `A`. - * Can be thought of as "can be the Target of a DataView". - * - * Chisel provides some implementations in [[DataProduct$ object DataProduct]] that are available - * by default in the implicit scope. - * - * @tparam A Type that has elements of type [[Data]] - * @see [[https://www.chisel-lang.org/chisel3/docs/explanations/dataview#dataproduct Detailed Documentation]] - */ -@implicitNotFound( - "Could not find implicit value for DataProduct[${A}].\n" + - "Please see https://www.chisel-lang.org/chisel3/docs/explanations/dataview#dataproduct" -) -trait DataProduct[-A] { - - /** Provides [[Data]] elements within some containing object - * - * @param a Containing object - * @param path Hierarchical path to current signal (for error reporting) - * @return Data elements and associated String paths (Strings for error reporting only!) - */ - def dataIterator(a: A, path: String): Iterator[(Data, String)] - - /** Returns a checker to test if the containing object contains a `Data` object - * @note Implementers may want to override if iterating on all `Data` is expensive for `A` and `A` - * will primarily be used in `PartialDataViews` - * @note The returned value is a function, not a true Set, but is describing the functionality of - * Set containment - * @param a Containing object - * @return A checker that itself returns True if a given `Data` is contained in `a` - * as determined by an `==` test - */ - def dataSet(a: A): Data => Boolean = dataIterator(a, "").map(_._1).toSet -} - -/** Low priority built-in implementations of [[DataProduct]] - * - * @note This trait exists so that `dataDataProduct` can be lower priority than `seqDataProduct` to resolve ambiguity - */ -sealed trait LowPriorityDataProduct { - - /** [[DataProduct]] implementation for [[Data]] */ - implicit val dataDataProduct: DataProduct[Data] = new DataProduct[Data] { - def dataIterator(a: Data, path: String): Iterator[(Data, String)] = - getRecursiveFields.lazily(a, path).iterator - } -} - -/** Encapsulating object for built-in implementations of [[DataProduct]] - * - * @note DataProduct implementations provided in this object are available in the implicit scope - */ -object DataProduct extends LowPriorityDataProduct { - - /** [[DataProduct]] implementation for [[BaseModule]] */ - implicit val userModuleDataProduct: DataProduct[BaseModule] = new DataProduct[BaseModule] { - def dataIterator(a: BaseModule, path: String): Iterator[(Data, String)] = { - a.getIds.iterator.flatMap { - case d: Data if d.getOptionRef.isDefined => // Using ref to decide if it's truly hardware in the module - Seq(d -> s"${path}.${d.instanceName}") - case b: BaseModule => dataIterator(b, s"$path.${b.instanceName}") - case _ => Seq.empty - } - } - // Overridden for performance - override def dataSet(a: BaseModule): Data => Boolean = { - val lastId = a._lastId // Not cheap to compute - // Return a function - e => e._id > a._id && e._id <= lastId - } - } - - /** [[DataProduct]] implementation for any `Seq[A]` where `A` has an implementation of `DataProduct`. */ - implicit def seqDataProduct[A: DataProduct]: DataProduct[Seq[A]] = new DataProduct[Seq[A]] { - def dataIterator(a: Seq[A], path: String): Iterator[(Data, String)] = { - val dpa = implicitly[DataProduct[A]] - a.iterator.zipWithIndex.flatMap { - case (elt, idx) => - dpa.dataIterator(elt, s"$path[$idx]") - } - } - } - - /** [[DataProduct]] implementation for any [[Tuple2]] where each field has an implementation of `DataProduct`. */ - implicit def tuple2DataProduct[A: DataProduct, B: DataProduct]: DataProduct[(A, B)] = new DataProduct[(A, B)] { - def dataIterator(tup: (A, B), path: String): Iterator[(Data, String)] = { - val dpa = implicitly[DataProduct[A]] - val dpb = implicitly[DataProduct[B]] - val (a, b) = tup - dpa.dataIterator(a, s"$path._1") ++ dpb.dataIterator(b, s"$path._2") - } - } - - /** [[DataProduct]] implementation for any [[Tuple3]] where each field has an implementation of `DataProduct`. */ - implicit def tuple3DataProduct[A: DataProduct, B: DataProduct, C: DataProduct]: DataProduct[(A, B, C)] = - new DataProduct[(A, B, C)] { - def dataIterator(tup: (A, B, C), path: String): Iterator[(Data, String)] = { - val dpa = implicitly[DataProduct[A]] - val dpb = implicitly[DataProduct[B]] - val dpc = implicitly[DataProduct[C]] - val (a, b, c) = tup - dpa.dataIterator(a, s"$path._1") ++ dpb.dataIterator(b, s"$path._2") ++ dpc.dataIterator(c, s"$path._3") - } - } - - /** [[DataProduct]] implementation for any [[Tuple4]] where each field has an implementation of `DataProduct`. */ - implicit def tuple4DataProduct[ - A: DataProduct, - B: DataProduct, - C: DataProduct, - D: DataProduct - ]: DataProduct[(A, B, C, D)] = - new DataProduct[(A, B, C, D)] { - def dataIterator(tup: (A, B, C, D), path: String): Iterator[(Data, String)] = { - val dpa = implicitly[DataProduct[A]] - val dpb = implicitly[DataProduct[B]] - val dpc = implicitly[DataProduct[C]] - val dpd = implicitly[DataProduct[D]] - val (a, b, c, d) = tup - dpa.dataIterator(a, s"$path._1") ++ - dpb.dataIterator(b, s"$path._2") ++ - dpc.dataIterator(c, s"$path._3") ++ - dpd.dataIterator(d, s"$path._4") - } - } - - /** [[DataProduct]] implementation for any [[Tuple5]] where each field has an implementation of `DataProduct`. */ - implicit def tuple5DataProduct[ - A: DataProduct, - B: DataProduct, - C: DataProduct, - D: DataProduct, - E: DataProduct - ]: DataProduct[(A, B, C, D, E)] = - new DataProduct[(A, B, C, D, E)] { - def dataIterator(tup: (A, B, C, D, E), path: String): Iterator[(Data, String)] = { - val dpa = implicitly[DataProduct[A]] - val dpb = implicitly[DataProduct[B]] - val dpc = implicitly[DataProduct[C]] - val dpd = implicitly[DataProduct[D]] - val dpe = implicitly[DataProduct[E]] - val (a, b, c, d, e) = tup - dpa.dataIterator(a, s"$path._1") ++ - dpb.dataIterator(b, s"$path._2") ++ - dpc.dataIterator(c, s"$path._3") ++ - dpd.dataIterator(d, s"$path._4") ++ - dpe.dataIterator(e, s"$path._5") - } - } - - /** [[DataProduct]] implementation for any [[Tuple6]] where each field has an implementation of `DataProduct`. */ - implicit def tuple6DataProduct[ - A: DataProduct, - B: DataProduct, - C: DataProduct, - D: DataProduct, - E: DataProduct, - F: DataProduct - ]: DataProduct[(A, B, C, D, E, F)] = - new DataProduct[(A, B, C, D, E, F)] { - def dataIterator(tup: (A, B, C, D, E, F), path: String): Iterator[(Data, String)] = { - val dpa = implicitly[DataProduct[A]] - val dpb = implicitly[DataProduct[B]] - val dpc = implicitly[DataProduct[C]] - val dpd = implicitly[DataProduct[D]] - val dpe = implicitly[DataProduct[E]] - val dpf = implicitly[DataProduct[F]] - val (a, b, c, d, e, f) = tup - dpa.dataIterator(a, s"$path._1") ++ - dpb.dataIterator(b, s"$path._2") ++ - dpc.dataIterator(c, s"$path._3") ++ - dpd.dataIterator(d, s"$path._4") ++ - dpe.dataIterator(e, s"$path._5") ++ - dpf.dataIterator(f, s"$path._6") - } - } - - /** [[DataProduct]] implementation for any [[Tuple7]] where each field has an implementation of `DataProduct`. */ - implicit def tuple7DataProduct[ - A: DataProduct, - B: DataProduct, - C: DataProduct, - D: DataProduct, - E: DataProduct, - F: DataProduct, - G: DataProduct - ]: DataProduct[(A, B, C, D, E, F, G)] = - new DataProduct[(A, B, C, D, E, F, G)] { - def dataIterator(tup: (A, B, C, D, E, F, G), path: String): Iterator[(Data, String)] = { - val dpa = implicitly[DataProduct[A]] - val dpb = implicitly[DataProduct[B]] - val dpc = implicitly[DataProduct[C]] - val dpd = implicitly[DataProduct[D]] - val dpe = implicitly[DataProduct[E]] - val dpf = implicitly[DataProduct[F]] - val dpg = implicitly[DataProduct[G]] - val (a, b, c, d, e, f, g) = tup - dpa.dataIterator(a, s"$path._1") ++ - dpb.dataIterator(b, s"$path._2") ++ - dpc.dataIterator(c, s"$path._3") ++ - dpd.dataIterator(d, s"$path._4") ++ - dpe.dataIterator(e, s"$path._5") ++ - dpf.dataIterator(f, s"$path._6") ++ - dpg.dataIterator(g, s"$path._7") - } - } - - /** [[DataProduct]] implementation for any [[Tuple8]] where each field has an implementation of `DataProduct`. */ - implicit def tuple8DataProduct[ - A: DataProduct, - B: DataProduct, - C: DataProduct, - D: DataProduct, - E: DataProduct, - F: DataProduct, - G: DataProduct, - H: DataProduct - ]: DataProduct[(A, B, C, D, E, F, G, H)] = - new DataProduct[(A, B, C, D, E, F, G, H)] { - def dataIterator(tup: (A, B, C, D, E, F, G, H), path: String): Iterator[(Data, String)] = { - val dpa = implicitly[DataProduct[A]] - val dpb = implicitly[DataProduct[B]] - val dpc = implicitly[DataProduct[C]] - val dpd = implicitly[DataProduct[D]] - val dpe = implicitly[DataProduct[E]] - val dpf = implicitly[DataProduct[F]] - val dpg = implicitly[DataProduct[G]] - val dph = implicitly[DataProduct[H]] - val (a, b, c, d, e, f, g, h) = tup - dpa.dataIterator(a, s"$path._1") ++ - dpb.dataIterator(b, s"$path._2") ++ - dpc.dataIterator(c, s"$path._3") ++ - dpd.dataIterator(d, s"$path._4") ++ - dpe.dataIterator(e, s"$path._5") ++ - dpf.dataIterator(f, s"$path._6") ++ - dpg.dataIterator(g, s"$path._7") ++ - dph.dataIterator(h, s"$path._8") - } - } - - /** [[DataProduct]] implementation for any [[Tuple9]] where each field has an implementation of `DataProduct`. */ - implicit def tuple9DataProduct[ - A: DataProduct, - B: DataProduct, - C: DataProduct, - D: DataProduct, - E: DataProduct, - F: DataProduct, - G: DataProduct, - H: DataProduct, - I: DataProduct - ]: DataProduct[(A, B, C, D, E, F, G, H, I)] = - new DataProduct[(A, B, C, D, E, F, G, H, I)] { - def dataIterator(tup: (A, B, C, D, E, F, G, H, I), path: String): Iterator[(Data, String)] = { - val dpa = implicitly[DataProduct[A]] - val dpb = implicitly[DataProduct[B]] - val dpc = implicitly[DataProduct[C]] - val dpd = implicitly[DataProduct[D]] - val dpe = implicitly[DataProduct[E]] - val dpf = implicitly[DataProduct[F]] - val dpg = implicitly[DataProduct[G]] - val dph = implicitly[DataProduct[H]] - val dpi = implicitly[DataProduct[I]] - val (a, b, c, d, e, f, g, h, i) = tup - dpa.dataIterator(a, s"$path._1") ++ - dpb.dataIterator(b, s"$path._2") ++ - dpc.dataIterator(c, s"$path._3") ++ - dpd.dataIterator(d, s"$path._4") ++ - dpe.dataIterator(e, s"$path._5") ++ - dpf.dataIterator(f, s"$path._6") ++ - dpg.dataIterator(g, s"$path._7") ++ - dph.dataIterator(h, s"$path._8") ++ - dpi.dataIterator(i, s"$path._9") - } - } - - /** [[DataProduct]] implementation for any [[Tuple9]] where each field has an implementation of `DataProduct`. */ - implicit def tuple10DataProduct[ - A: DataProduct, - B: DataProduct, - C: DataProduct, - D: DataProduct, - E: DataProduct, - F: DataProduct, - G: DataProduct, - H: DataProduct, - I: DataProduct, - J: DataProduct - ]: DataProduct[(A, B, C, D, E, F, G, H, I, J)] = - new DataProduct[(A, B, C, D, E, F, G, H, I, J)] { - def dataIterator(tup: (A, B, C, D, E, F, G, H, I, J), path: String): Iterator[(Data, String)] = { - val dpa = implicitly[DataProduct[A]] - val dpb = implicitly[DataProduct[B]] - val dpc = implicitly[DataProduct[C]] - val dpd = implicitly[DataProduct[D]] - val dpe = implicitly[DataProduct[E]] - val dpf = implicitly[DataProduct[F]] - val dpg = implicitly[DataProduct[G]] - val dph = implicitly[DataProduct[H]] - val dpi = implicitly[DataProduct[I]] - val dpj = implicitly[DataProduct[J]] - val (a, b, c, d, e, f, g, h, i, j) = tup - dpa.dataIterator(a, s"$path._1") ++ - dpb.dataIterator(b, s"$path._2") ++ - dpc.dataIterator(c, s"$path._3") ++ - dpd.dataIterator(d, s"$path._4") ++ - dpe.dataIterator(e, s"$path._5") ++ - dpf.dataIterator(f, s"$path._6") ++ - dpg.dataIterator(g, s"$path._7") ++ - dph.dataIterator(h, s"$path._8") ++ - dpi.dataIterator(i, s"$path._9") ++ - dpj.dataIterator(j, s"$path._10") - } - } -} diff --git a/core/src/main/scala/chisel3/experimental/dataview/DataView.scala b/core/src/main/scala/chisel3/experimental/dataview/DataView.scala deleted file mode 100644 index cc555b11..00000000 --- a/core/src/main/scala/chisel3/experimental/dataview/DataView.scala +++ /dev/null @@ -1,618 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 - -package chisel3.experimental.dataview - -import chisel3._ -import chisel3.experimental.DataMirror.internal.chiselTypeClone -import chisel3.experimental.{HWTuple10, HWTuple2, HWTuple3, HWTuple4, HWTuple5, HWTuple6, HWTuple7, HWTuple8, HWTuple9} -import chisel3.internal.sourceinfo.{SourceInfo, UnlocatableSourceInfo} -import chisel3.ExplicitCompileOptions.Strict - -import scala.reflect.runtime.universe.WeakTypeTag -import annotation.implicitNotFound - -/** Mapping between a target type `T` and a view type `V` - * - * Enables calling `.viewAs[T]` on instances of the target type. - * - * ==Detailed documentation== - * - [[https://www.chisel-lang.org/chisel3/docs/explanations/dataview Explanation]] - * - [[https://www.chisel-lang.org/chisel3/docs/cookbooks/dataview Cookbook]] - * - * @example {{{ - * class Foo(val w: Int) extends Bundle { - * val a = UInt(w.W) - * } - * class Bar(val w: Int) extends Bundle { - * val b = UInt(w.W) - * } - * // DataViews are created using factory methods in the companion object - * implicit val view = DataView[Foo, Bar]( - * // The first argument is a function constructing a Foo from a Bar - * foo => new Bar(foo.w) - * // The remaining arguments are a variable number of field pairings - * _.a -> _.b - * ) - * }}} - * - * @tparam T Target type (must have an implementation of [[DataProduct]]) - * @tparam V View type - * @see [[DataView$ object DataView]] for factory methods - * @see [[PartialDataView object PartialDataView]] for defining non-total `DataViews` - */ -@implicitNotFound( - "Could not find implicit value for DataView[${T}, ${V}].\n" + - "Please see https://www.chisel-lang.org/chisel3/docs/explanations/dataview" -) -sealed class DataView[T: DataProduct, V <: Data] private[chisel3] ( - /** Function constructing an object of the View type from an object of the Target type */ - private[chisel3] val mkView: T => V, - /** Function that returns corresponding fields of the target and view */ - private[chisel3] val mapping: (T, V) => Iterable[(Data, Data)], - // Aliasing this with a def below to make the ScalaDoc show up for the field - _total: Boolean -)( - implicit private[chisel3] val sourceInfo: SourceInfo) { - - /** Indicates if the mapping contains every field of the target */ - def total: Boolean = _total - - override def toString: String = { - val base = sourceInfo.makeMessage(x => x) - val loc = if (base.nonEmpty) base else "@unknown" - val name = if (total) "DataView" else "PartialDataView" - s"$name(defined $loc)" - } - - /** Compose two `DataViews` together to construct a view from the target of this `DataView` to the - * view type of the second `DataView` - * - * @param g a DataView from `V` to new view-type `V2` - * @tparam V2 View type of `DataView` `g` - * @return a new `DataView` from the original `T` to new view-type `V2` - */ - def andThen[V2 <: Data](g: DataView[V, V2])(implicit sourceInfo: SourceInfo): DataView[T, V2] = { - val self = this - // We have to pass the DataProducts and DataViews manually to .viewAs below - val tdp = implicitly[DataProduct[T]] - val vdp = implicitly[DataProduct[V]] - new DataView[T, V2]( - t => g.mkView(mkView(t)), - { case (t, v2) => List(t.viewAs[V](tdp, self).viewAs[V2](vdp, g) -> v2) }, - this.total && g.total - ) { - override def toString: String = s"$self andThen $g" - } - } -} - -/** Factory methods for constructing [[DataView]]s, see class for example use */ -object DataView { - - /** Default factory method, alias for [[pairs]] */ - def apply[T: DataProduct, V <: Data]( - mkView: T => V, - pairs: ((T, V) => (Data, Data))* - )( - implicit sourceInfo: SourceInfo - ): DataView[T, V] = - DataView.pairs(mkView, pairs: _*) - - /** Construct [[DataView]]s with pairs of functions from the target and view to corresponding fields */ - def pairs[T: DataProduct, V <: Data]( - mkView: T => V, - pairs: ((T, V) => (Data, Data))* - )( - implicit sourceInfo: SourceInfo - ): DataView[T, V] = - mapping(mkView: T => V, swizzle(pairs)) - - /** More general factory method for complex mappings */ - def mapping[T: DataProduct, V <: Data]( - mkView: T => V, - mapping: (T, V) => Iterable[(Data, Data)] - )( - implicit sourceInfo: SourceInfo - ): DataView[T, V] = - new DataView[T, V](mkView, mapping, _total = true) - - /** Provides `invert` for invertible [[DataView]]s - * - * This must be done as an extension method because it applies an addition constraint on the `Target` - * type parameter, namely that it must be a subtype of [[Data]]. - * - * @note [[PartialDataView]]s are **not** invertible and will result in an elaboration time exception - */ - implicit class InvertibleDataView[T <: Data: WeakTypeTag, V <: Data: WeakTypeTag](view: DataView[T, V]) { - def invert(mkView: V => T): DataView[V, T] = { - // It would've been nice to make this a compiler error, but it's unclear how to make that work. - // We tried having separate TotalDataView and PartialDataView and only defining inversion for - // TotalDataView. For some reason, implicit resolution wouldn't invert TotalDataViews. This is - // probably because it was looking for the super-type DataView and since invertDataView was - // only defined on TotalDataView, it wasn't included in implicit resolution. Thus we end up - // with a runtime check. - if (!view.total) { - val tt = implicitly[WeakTypeTag[T]].tpe - val vv = implicitly[WeakTypeTag[V]].tpe - val msg = s"Cannot invert '$view' as it is non-total.\n Try providing a DataView[$vv, $tt]." + - s"\n Please see https://www.chisel-lang.org/chisel3/docs/explanations/dataview." - throw InvalidViewException(msg) - } - implicit val sourceInfo = view.sourceInfo - new DataView[V, T](mkView, swapArgs(view.mapping), view.total) - } - } - - private[dataview] def swizzle[A, B, C, D](fs: Iterable[(A, B) => (C, D)]): (A, B) => Iterable[(C, D)] = { - case (a, b) => fs.map(f => f(a, b)) - } - - private def swapArgs[A, B, C, D](f: (A, B) => Iterable[(C, D)]): (B, A) => Iterable[(D, C)] = { - case (b, a) => f(a, b).map(_.swap) - } - - // ****************************** Built-in Implementations of DataView ****************************** - // Sort of the "Standard library" implementations - - /** All Chisel Data are viewable as their own type */ - implicit def identityView[A <: Data](implicit sourceInfo: SourceInfo): DataView[A, A] = - DataView[A, A](chiselTypeOf.apply, { case (x, y) => (x, y) }) - - /** Provides `DataView[Seq[A], Vec[B]]` for all `A` such that there exists `DataView[A, B]` */ - implicit def seqDataView[A: DataProduct, B <: Data]( - implicit dv: DataView[A, B], - sourceInfo: SourceInfo - ): DataView[Seq[A], Vec[B]] = { - // TODO this would need a better way to determine the prototype for the Vec - DataView.mapping[Seq[A], Vec[B]]( - xs => Vec(xs.size, chiselTypeClone(xs.head.viewAs[B]))(sourceInfo, Strict), // xs.head is not correct in general - { case (s, v) => s.zip(v).map { case (a, b) => a.viewAs[B] -> b } } - ) - } - - /** Provides implementations of [[DataView]] for [[Tuple2]] to [[HWTuple2]] */ - implicit def tuple2DataView[T1: DataProduct, T2: DataProduct, V1 <: Data, V2 <: Data]( - implicit v1: DataView[T1, V1], - v2: DataView[T2, V2], - sourceInfo: SourceInfo - ): DataView[(T1, T2), HWTuple2[V1, V2]] = - DataView.mapping( - { case (a, b) => new HWTuple2(a.viewAs[V1].cloneType, b.viewAs[V2].cloneType) }, - { - case ((a, b), hwt) => - Seq(a.viewAs[V1] -> hwt._1, b.viewAs[V2] -> hwt._2) - } - ) - - /** Provides implementations of [[DataView]] for [[Tuple3]] to [[HWTuple3]] */ - implicit def tuple3DataView[T1: DataProduct, T2: DataProduct, T3: DataProduct, V1 <: Data, V2 <: Data, V3 <: Data]( - implicit v1: DataView[T1, V1], - v2: DataView[T2, V2], - v3: DataView[T3, V3], - sourceInfo: SourceInfo - ): DataView[(T1, T2, T3), HWTuple3[V1, V2, V3]] = - DataView.mapping( - { case (a, b, c) => new HWTuple3(a.viewAs[V1].cloneType, b.viewAs[V2].cloneType, c.viewAs[V3].cloneType) }, - { - case ((a, b, c), hwt) => - Seq(a.viewAs[V1] -> hwt._1, b.viewAs[V2] -> hwt._2, c.viewAs[V3] -> hwt._3) - } - ) - - /** Provides implementations of [[DataView]] for [[Tuple4]] to [[HWTuple4]] */ - implicit def tuple4DataView[ - T1: DataProduct, - T2: DataProduct, - T3: DataProduct, - T4: DataProduct, - V1 <: Data, - V2 <: Data, - V3 <: Data, - V4 <: Data - ]( - implicit v1: DataView[T1, V1], - v2: DataView[T2, V2], - v3: DataView[T3, V3], - v4: DataView[T4, V4], - sourceInfo: SourceInfo - ): DataView[(T1, T2, T3, T4), HWTuple4[V1, V2, V3, V4]] = - DataView.mapping( - { - case (a, b, c, d) => - new HWTuple4(a.viewAs[V1].cloneType, b.viewAs[V2].cloneType, c.viewAs[V3].cloneType, d.viewAs[V4].cloneType) - }, - { - case ((a, b, c, d), hwt) => - Seq(a.viewAs[V1] -> hwt._1, b.viewAs[V2] -> hwt._2, c.viewAs[V3] -> hwt._3, d.viewAs[V4] -> hwt._4) - } - ) - - /** Provides implementations of [[DataView]] for [[Tuple5]] to [[HWTuple5]] */ - implicit def tuple5DataView[ - T1: DataProduct, - T2: DataProduct, - T3: DataProduct, - T4: DataProduct, - T5: DataProduct, - V1 <: Data, - V2 <: Data, - V3 <: Data, - V4 <: Data, - V5 <: Data - ]( - implicit v1: DataView[T1, V1], - v2: DataView[T2, V2], - v3: DataView[T3, V3], - v4: DataView[T4, V4], - v5: DataView[T5, V5], - sourceInfo: SourceInfo - ): DataView[(T1, T2, T3, T4, T5), HWTuple5[V1, V2, V3, V4, V5]] = { - DataView.mapping( - { - case tup: Tuple5[T1, T2, T3, T4, T5] => - val (a, b, c, d, e) = tup - new HWTuple5( - a.viewAs[V1].cloneType, - b.viewAs[V2].cloneType, - c.viewAs[V3].cloneType, - d.viewAs[V4].cloneType, - e.viewAs[V5].cloneType - ) - }, - { - case ((a, b, c, d, e), hwt) => - Seq( - a.viewAs[V1] -> hwt._1, - b.viewAs[V2] -> hwt._2, - c.viewAs[V3] -> hwt._3, - d.viewAs[V4] -> hwt._4, - e.viewAs[V5] -> hwt._5 - ) - } - ) - } - - /** Provides implementations of [[DataView]] for [[Tuple6]] to [[HWTuple6]] */ - implicit def tuple6DataView[ - T1: DataProduct, - T2: DataProduct, - T3: DataProduct, - T4: DataProduct, - T5: DataProduct, - T6: DataProduct, - V1 <: Data, - V2 <: Data, - V3 <: Data, - V4 <: Data, - V5 <: Data, - V6 <: Data - ]( - implicit v1: DataView[T1, V1], - v2: DataView[T2, V2], - v3: DataView[T3, V3], - v4: DataView[T4, V4], - v5: DataView[T5, V5], - v6: DataView[T6, V6], - sourceInfo: SourceInfo - ): DataView[(T1, T2, T3, T4, T5, T6), HWTuple6[V1, V2, V3, V4, V5, V6]] = - DataView.mapping( - { - case (a, b, c, d, e, f) => - new HWTuple6( - a.viewAs[V1].cloneType, - b.viewAs[V2].cloneType, - c.viewAs[V3].cloneType, - d.viewAs[V4].cloneType, - e.viewAs[V5].cloneType, - f.viewAs[V6].cloneType - ) - }, - { - case ((a, b, c, d, e, f), hwt) => - Seq( - a.viewAs[V1] -> hwt._1, - b.viewAs[V2] -> hwt._2, - c.viewAs[V3] -> hwt._3, - d.viewAs[V4] -> hwt._4, - e.viewAs[V5] -> hwt._5, - f.viewAs[V6] -> hwt._6 - ) - } - ) - - /** Provides implementations of [[DataView]] for [[Tuple7]] to [[HWTuple7]] */ - implicit def tuple7DataView[ - T1: DataProduct, - T2: DataProduct, - T3: DataProduct, - T4: DataProduct, - T5: DataProduct, - T6: DataProduct, - T7: DataProduct, - V1 <: Data, - V2 <: Data, - V3 <: Data, - V4 <: Data, - V5 <: Data, - V6 <: Data, - V7 <: Data - ]( - implicit v1: DataView[T1, V1], - v2: DataView[T2, V2], - v3: DataView[T3, V3], - v4: DataView[T4, V4], - v5: DataView[T5, V5], - v6: DataView[T6, V6], - v7: DataView[T7, V7], - sourceInfo: SourceInfo - ): DataView[(T1, T2, T3, T4, T5, T6, T7), HWTuple7[V1, V2, V3, V4, V5, V6, V7]] = - DataView.mapping( - { - case (a, b, c, d, e, f, g) => - new HWTuple7( - a.viewAs[V1].cloneType, - b.viewAs[V2].cloneType, - c.viewAs[V3].cloneType, - d.viewAs[V4].cloneType, - e.viewAs[V5].cloneType, - f.viewAs[V6].cloneType, - g.viewAs[V7].cloneType - ) - }, - { - case ((a, b, c, d, e, f, g), hwt) => - Seq( - a.viewAs[V1] -> hwt._1, - b.viewAs[V2] -> hwt._2, - c.viewAs[V3] -> hwt._3, - d.viewAs[V4] -> hwt._4, - e.viewAs[V5] -> hwt._5, - f.viewAs[V6] -> hwt._6, - g.viewAs[V7] -> hwt._7 - ) - } - ) - - /** Provides implementations of [[DataView]] for [[Tuple8]] to [[HWTuple8]] */ - implicit def tuple8DataView[ - T1: DataProduct, - T2: DataProduct, - T3: DataProduct, - T4: DataProduct, - T5: DataProduct, - T6: DataProduct, - T7: DataProduct, - T8: DataProduct, - V1 <: Data, - V2 <: Data, - V3 <: Data, - V4 <: Data, - V5 <: Data, - V6 <: Data, - V7 <: Data, - V8 <: Data - ]( - implicit v1: DataView[T1, V1], - v2: DataView[T2, V2], - v3: DataView[T3, V3], - v4: DataView[T4, V4], - v5: DataView[T5, V5], - v6: DataView[T6, V6], - v7: DataView[T7, V7], - v8: DataView[T8, V8], - sourceInfo: SourceInfo - ): DataView[(T1, T2, T3, T4, T5, T6, T7, T8), HWTuple8[V1, V2, V3, V4, V5, V6, V7, V8]] = - DataView.mapping( - { - case (a, b, c, d, e, f, g, h) => - new HWTuple8( - a.viewAs[V1].cloneType, - b.viewAs[V2].cloneType, - c.viewAs[V3].cloneType, - d.viewAs[V4].cloneType, - e.viewAs[V5].cloneType, - f.viewAs[V6].cloneType, - g.viewAs[V7].cloneType, - h.viewAs[V8].cloneType - ) - }, - { - case ((a, b, c, d, e, f, g, h), hwt) => - Seq( - a.viewAs[V1] -> hwt._1, - b.viewAs[V2] -> hwt._2, - c.viewAs[V3] -> hwt._3, - d.viewAs[V4] -> hwt._4, - e.viewAs[V5] -> hwt._5, - f.viewAs[V6] -> hwt._6, - g.viewAs[V7] -> hwt._7, - h.viewAs[V8] -> hwt._8 - ) - } - ) - - /** Provides implementations of [[DataView]] for [[Tuple9]] to [[HWTuple9]] */ - implicit def tuple9DataView[ - T1: DataProduct, - T2: DataProduct, - T3: DataProduct, - T4: DataProduct, - T5: DataProduct, - T6: DataProduct, - T7: DataProduct, - T8: DataProduct, - T9: DataProduct, - V1 <: Data, - V2 <: Data, - V3 <: Data, - V4 <: Data, - V5 <: Data, - V6 <: Data, - V7 <: Data, - V8 <: Data, - V9 <: Data - ]( - implicit v1: DataView[T1, V1], - v2: DataView[T2, V2], - v3: DataView[T3, V3], - v4: DataView[T4, V4], - v5: DataView[T5, V5], - v6: DataView[T6, V6], - v7: DataView[T7, V7], - v8: DataView[T8, V8], - v9: DataView[T9, V9], - sourceInfo: SourceInfo - ): DataView[(T1, T2, T3, T4, T5, T6, T7, T8, T9), HWTuple9[V1, V2, V3, V4, V5, V6, V7, V8, V9]] = - DataView.mapping( - { - case (a, b, c, d, e, f, g, h, i) => - new HWTuple9( - a.viewAs[V1].cloneType, - b.viewAs[V2].cloneType, - c.viewAs[V3].cloneType, - d.viewAs[V4].cloneType, - e.viewAs[V5].cloneType, - f.viewAs[V6].cloneType, - g.viewAs[V7].cloneType, - h.viewAs[V8].cloneType, - i.viewAs[V9].cloneType - ) - }, - { - case ((a, b, c, d, e, f, g, h, i), hwt) => - Seq( - a.viewAs[V1] -> hwt._1, - b.viewAs[V2] -> hwt._2, - c.viewAs[V3] -> hwt._3, - d.viewAs[V4] -> hwt._4, - e.viewAs[V5] -> hwt._5, - f.viewAs[V6] -> hwt._6, - g.viewAs[V7] -> hwt._7, - h.viewAs[V8] -> hwt._8, - i.viewAs[V9] -> hwt._9 - ) - } - ) - - /** Provides implementations of [[DataView]] for [[Tuple10]] to [[HWTuple10]] */ - implicit def tuple10DataView[ - T1: DataProduct, - T2: DataProduct, - T3: DataProduct, - T4: DataProduct, - T5: DataProduct, - T6: DataProduct, - T7: DataProduct, - T8: DataProduct, - T9: DataProduct, - T10: DataProduct, - V1 <: Data, - V2 <: Data, - V3 <: Data, - V4 <: Data, - V5 <: Data, - V6 <: Data, - V7 <: Data, - V8 <: Data, - V9 <: Data, - V10 <: Data - ]( - implicit v1: DataView[T1, V1], - v2: DataView[T2, V2], - v3: DataView[T3, V3], - v4: DataView[T4, V4], - v5: DataView[T5, V5], - v6: DataView[T6, V6], - v7: DataView[T7, V7], - v8: DataView[T8, V8], - v9: DataView[T9, V9], - v10: DataView[T10, V10], - sourceInfo: SourceInfo - ): DataView[(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10), HWTuple10[V1, V2, V3, V4, V5, V6, V7, V8, V9, V10]] = - DataView.mapping( - { - case (a, b, c, d, e, f, g, h, i, j) => - new HWTuple10( - a.viewAs[V1].cloneType, - b.viewAs[V2].cloneType, - c.viewAs[V3].cloneType, - d.viewAs[V4].cloneType, - e.viewAs[V5].cloneType, - f.viewAs[V6].cloneType, - g.viewAs[V7].cloneType, - h.viewAs[V8].cloneType, - i.viewAs[V9].cloneType, - j.viewAs[V10].cloneType - ) - }, - { - case ((a, b, c, d, e, f, g, h, i, j), hwt) => - Seq( - a.viewAs[V1] -> hwt._1, - b.viewAs[V2] -> hwt._2, - c.viewAs[V3] -> hwt._3, - d.viewAs[V4] -> hwt._4, - e.viewAs[V5] -> hwt._5, - f.viewAs[V6] -> hwt._6, - g.viewAs[V7] -> hwt._7, - h.viewAs[V8] -> hwt._8, - i.viewAs[V9] -> hwt._9, - j.viewAs[V10] -> hwt._10 - ) - } - ) -} - -/** Factory methods for constructing non-total [[DataView]]s */ -object PartialDataView { - - /** Default factory method, alias for [[pairs]] */ - def apply[T: DataProduct, V <: Data]( - mkView: T => V, - pairs: ((T, V) => (Data, Data))* - )( - implicit sourceInfo: SourceInfo - ): DataView[T, V] = - PartialDataView.pairs(mkView, pairs: _*) - - /** Construct [[DataView]]s with pairs of functions from the target and view to corresponding fields */ - def pairs[T: DataProduct, V <: Data]( - mkView: T => V, - pairs: ((T, V) => (Data, Data))* - )( - implicit sourceInfo: SourceInfo - ): DataView[T, V] = - mapping(mkView, DataView.swizzle(pairs)) - - /** More general factory method for complex mappings */ - def mapping[T: DataProduct, V <: Data]( - mkView: T => V, - mapping: (T, V) => Iterable[(Data, Data)] - )( - implicit sourceInfo: SourceInfo - ): DataView[T, V] = - new DataView[T, V](mkView, mapping, _total = false) - - /** Constructs a non-total [[DataView]] mapping from a [[Bundle]] type to a parent [[Bundle]] type - * - * @param mkView a function constructing an instance `V` from an instance of `T` - * @return the [[DataView]] that enables viewing instances of a [[Bundle]] as instances of a parent type - */ - def supertype[T <: Bundle, V <: Bundle]( - mkView: T => V - )( - implicit ev: SubTypeOf[T, V], - sourceInfo: SourceInfo - ): DataView[T, V] = - mapping[T, V]( - mkView, - { - case (a, b) => - val aElts = a.elements - val bElts = b.elements - val bKeys = bElts.keySet - val keys = aElts.keysIterator.filter(bKeys.contains) - keys.map(k => aElts(k) -> bElts(k)).toSeq - } - ) -} diff --git a/core/src/main/scala/chisel3/experimental/dataview/package.scala b/core/src/main/scala/chisel3/experimental/dataview/package.scala deleted file mode 100644 index a52e88cf..00000000 --- a/core/src/main/scala/chisel3/experimental/dataview/package.scala +++ /dev/null @@ -1,268 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 - -package chisel3.experimental - -import chisel3._ -import chisel3.internal._ -import chisel3.internal.sourceinfo.SourceInfo - -import scala.annotation.{implicitNotFound, tailrec} -import scala.collection.mutable -import scala.collection.immutable.LazyList // Needed for 2.12 alias - -package object dataview { - case class InvalidViewException(message: String) extends ChiselException(message) - - /** Provides `viewAs` for types that have an implementation of [[DataProduct]] - * - * Calling `viewAs` also requires an implementation of [[DataView]] for the target type - */ - implicit class DataViewable[T](target: T) { - def viewAs[V <: Data](implicit dataproduct: DataProduct[T], dataView: DataView[T, V]): V = { - // TODO put a try catch here for ExpectedHardwareException and perhaps others - // It's likely users will accidentally use chiselTypeOf or something that may error, - // The right thing to use is DataMirror...chiselTypeClone because of composition with DataView.andThen - // Another option is that .andThen could give a fake binding making chiselTypeOfs in the user code safe - val result: V = dataView.mkView(target) - requireIsChiselType(result, "viewAs") - - doBind(target, result, dataView) - - // Setting the parent marks these Data as Views - result.setAllParents(Some(ViewParent)) - // The names of views do not matter except for when a view is annotated. For Views that correspond - // To a single Data, we just forward the name of the Target. For Views that correspond to more - // than one Data, we return this assigned name but rename it in the Convert stage - result.forceName("view", Builder.viewNamespace) - result - } - } - - // This private type alias lets us provide a custom error message for misuing the .viewAs for upcasting Bundles - @implicitNotFound( - "${A} is not a subtype of ${B}! Did you mean .viewAs[${B}]? " + - "Please see https://www.chisel-lang.org/chisel3/docs/cookbooks/dataview" - ) - private[dataview] type SubTypeOf[A, B] = A <:< B - - /** Provides `viewAsSupertype` for subclasses of [[Bundle]] */ - implicit class BundleUpcastable[T <: Bundle](target: T) { - - /** View a [[Bundle]] or [[Record]] as a parent type (upcast) */ - def viewAsSupertype[V <: Bundle](proto: V)(implicit ev: SubTypeOf[T, V], sourceInfo: SourceInfo): V = { - implicit val dataView = PartialDataView.supertype[T, V](_ => proto) - target.viewAs[V] - } - } - - private def nonTotalViewException( - dataView: DataView[_, _], - target: Any, - view: Data, - targetFields: Seq[String], - viewFields: Seq[String] - ) = { - def missingMsg(name: String, fields: Seq[String]): Option[String] = { - val str = fields.mkString(", ") - fields.size match { - case 0 => None - case 1 => Some(s"$name field '$str' is missing") - case _ => Some(s"$name fields '$str' are missing") - } - } - val vs = missingMsg("view", viewFields) - val ts = missingMsg("target", targetFields) - val reasons = (ts ++ vs).mkString(" and ").capitalize - val suggestion = if (ts.nonEmpty) "\n If the view *should* be non-total, try a 'PartialDataView'." else "" - val msg = s"Viewing $target as $view is non-Total!\n $reasons.\n DataView used is $dataView.$suggestion" - throw InvalidViewException(msg) - } - - // TODO should this be moved to class Aggregate / can it be unified with Aggregate.bind? - private def doBind[T: DataProduct, V <: Data](target: T, view: V, dataView: DataView[T, V]): Unit = { - val mapping = dataView.mapping(target, view) - val total = dataView.total - // Lookups to check the mapping results - val viewFieldLookup: Map[Data, String] = getRecursiveFields(view, "_").toMap - val targetContains: Data => Boolean = implicitly[DataProduct[T]].dataSet(target) - - // Resulting bindings for each Element of the View - // Kept separate from Aggregates for totality checking - val elementBindings = - new mutable.HashMap[Data, mutable.ListBuffer[Element]] ++ - viewFieldLookup.view.collect { case (elt: Element, _) => elt } - .map(_ -> new mutable.ListBuffer[Element]) - - // Record any Aggregates that correspond 1:1 for reification - // Using Data instead of Aggregate to avoid unnecessary checks - val aggregateMappings = mutable.ArrayBuffer.empty[(Data, Data)] - - def viewFieldName(d: Data): String = - viewFieldLookup.get(d).map(_ + " ").getOrElse("") + d.toString - - // Helper for recording the binding of each - def onElt(te: Element, ve: Element): Unit = { - // TODO can/should we aggregate these errors? - def err(name: String, arg: Data) = - throw InvalidViewException(s"View mapping must only contain Elements within the $name, got $arg") - - // The elements may themselves be views, look through the potential chain of views for the Elements - // that are actually members of the target or view - val tex = unfoldView(te).find(targetContains).getOrElse(err("Target", te)) - val vex = unfoldView(ve).find(viewFieldLookup.contains).getOrElse(err("View", ve)) - - if (tex.getClass != vex.getClass) { - val fieldName = viewFieldName(vex) - throw InvalidViewException(s"Field $fieldName specified as view of non-type-equivalent value $tex") - } - // View width must be unknown or match target width - if (vex.widthKnown && vex.width != tex.width) { - def widthAsString(x: Element) = x.widthOption.map("<" + _ + ">").getOrElse("") - val fieldName = viewFieldName(vex) - val vwidth = widthAsString(vex) - val twidth = widthAsString(tex) - throw InvalidViewException( - s"View field $fieldName has width ${vwidth} that is incompatible with target value $tex's width ${twidth}" - ) - } - elementBindings(vex) += tex - } - - mapping.foreach { - // Special cased because getMatchedFields checks typeEquivalence on Elements (and is used in Aggregate path) - // Also saves object allocations on common case of Elements - case (ae: Element, be: Element) => onElt(ae, be) - - case (aa: Aggregate, ba: Aggregate) => - if (!ba.typeEquivalent(aa)) { - val fieldName = viewFieldLookup(ba) - throw InvalidViewException(s"field $fieldName specified as view of non-type-equivalent value $aa") - } - getMatchedFields(aa, ba).foreach { - case (aelt: Element, belt: Element) => onElt(aelt, belt) - case (t, v) => aggregateMappings += (v -> t) - } - } - - // Errors in totality of the View, use var List to keep fast path cheap (no allocation) - var viewNonTotalErrors: List[Data] = Nil - var targetNonTotalErrors: List[String] = Nil - - val targetSeen: Option[mutable.Set[Data]] = if (total) Some(mutable.Set.empty[Data]) else None - - val elementResult = elementBindings.map { - case (data, targets) => - val targetsx = targets match { - case collection.Seq(target: Element) => target - case collection.Seq() => - viewNonTotalErrors = data :: viewNonTotalErrors - data.asInstanceOf[Element] // Return the Data itself, will error after this map, cast is safe - case x => - throw InvalidViewException(s"Got $x, expected Seq(_: Direct)") - } - // TODO record and report aliasing errors - targetSeen.foreach(_ += targetsx) - data -> targetsx - }.toMap - - // Check for totality of Target - targetSeen.foreach { seen => - val lookup = implicitly[DataProduct[T]].dataIterator(target, "_") - for (missed <- lookup.collect { case (d: Element, name) if !seen(d) => name }) { - targetNonTotalErrors = missed :: targetNonTotalErrors - } - } - if (viewNonTotalErrors != Nil || targetNonTotalErrors != Nil) { - val viewErrors = viewNonTotalErrors.map(f => viewFieldLookup.getOrElse(f, f.toString)) - nonTotalViewException(dataView, target, view, targetNonTotalErrors, viewErrors) - } - - view match { - case elt: Element => view.bind(ViewBinding(elementResult(elt))) - case agg: Aggregate => - // Don't forget the potential mapping of the view to the target! - target match { - case d: Data if total => - aggregateMappings += (agg -> d) - case _ => - } - - val fullResult = elementResult ++ aggregateMappings - - // We need to record any Aggregates that don't have a 1-1 mapping (including the view - // itself) - getRecursiveFields.lazily(view, "_").foreach { - case (unnamed: Aggregate, _) if !fullResult.contains(unnamed) => - Builder.unnamedViews += unnamed - case _ => // Do nothing - } - agg.bind(AggregateViewBinding(fullResult)) - } - } - - // Traces an Element that may (or may not) be a view until it no longer maps - // Inclusive of the argument - private def unfoldView(elt: Element): LazyList[Element] = { - def rec(e: Element): LazyList[Element] = e.topBindingOpt match { - case Some(ViewBinding(target)) => target #:: rec(target) - case Some(avb: AggregateViewBinding) => - val target = avb.lookup(e).get - target #:: rec(target) - case Some(_) | None => LazyList.empty - } - elt #:: rec(elt) - } - - // Safe for all Data - private[chisel3] def isView(d: Data): Boolean = d._parent.contains(ViewParent) - - /** Turn any [[Element]] that could be a View into a concrete Element - * - * This is the fundamental "unwrapping" or "tracing" primitive operation for handling Views within - * Chisel. - */ - private[chisel3] def reify(elt: Element): Element = - reify(elt, elt.topBinding) - - /** Turn any [[Element]] that could be a View into a concrete Element - * - * This is the fundamental "unwrapping" or "tracing" primitive operation for handling Views within - * Chisel. - */ - @tailrec private[chisel3] def reify(elt: Element, topBinding: TopBinding): Element = - topBinding match { - case ViewBinding(target) => reify(target, elt.topBinding) - case _ => elt - } - - /** Determine the target of a View if it is a single Target - * - * @note An Aggregate may be a view of unrelated [[Data]] (eg. like a Seq or tuple) and thus this - * there is no single Data representing the Target and this function will return None - * @return The single Data target of this view or None if a single Data doesn't exist - */ - private[chisel3] def reifySingleData(data: Data): Option[Data] = { - val candidate: Option[Data] = - data.topBindingOpt match { - case None => None - case Some(ViewBinding(target)) => Some(target) - case Some(AggregateViewBinding(lookup)) => lookup.get(data) - case Some(_) => None - } - candidate.flatMap { d => - // Candidate may itself be a view, keep tracing in those cases - if (isView(d)) reifySingleData(d) else Some(d) - } - } - - /** Determine the target of a View if it is a single Target - * - * @note An Aggregate may be a view of unrelated [[Data]] (eg. like a Seq or tuple) and thus this - * there is no single Data representing the Target and this function will return None - * @return The single Data target of this view or None if a single Data doesn't exist - */ - private[chisel3] def reifyToAggregate(data: Data): Option[Aggregate] = reifySingleData(data) match { - case Some(a: Aggregate) => Some(a) - case other => None - } -} diff --git a/core/src/main/scala/chisel3/experimental/hierarchy/Definition.scala b/core/src/main/scala/chisel3/experimental/hierarchy/Definition.scala deleted file mode 100644 index 99eacc7d..00000000 --- a/core/src/main/scala/chisel3/experimental/hierarchy/Definition.scala +++ /dev/null @@ -1,126 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 - -package chisel3.experimental.hierarchy - -import scala.language.experimental.macros -import chisel3._ - -import scala.collection.mutable.HashMap -import chisel3.internal.{Builder, DynamicContext} -import chisel3.internal.sourceinfo.{DefinitionTransform, DefinitionWrapTransform, SourceInfo} -import chisel3.experimental.BaseModule -import chisel3.internal.BaseModule.IsClone -import firrtl.annotations.{IsModule, ModuleTarget} -import firrtl.annotations.{IsModule, ModuleTarget, NoTargetAnnotation} - -/** User-facing Definition type. - * Represents a definition of an object of type [[A]] which are marked as @instantiable - * Can be created using Definition.apply method. - * - * These definitions are then used to create multiple [[Instance]]s. - * - * @param underlying The internal representation of the definition, which may be either be directly the object, or a clone of an object - */ -final case class Definition[+A] private[chisel3] (private[chisel3] underlying: Underlying[A]) - extends IsLookupable - with SealedHierarchy[A] { - - /** Used by Chisel's internal macros. DO NOT USE in your normal Chisel code!!! - * Instead, mark the field you are accessing with [[@public]] - * - * Given a selector function (that) which selects a member from the original, return the - * corresponding member from the instance. - * - * Our @instantiable and @public macros generate the calls to this apply method - * - * By calling this function, we summon the proper Lookupable typeclass from our implicit scope. - * - * @param that a user-specified lookup function - * @param lookup typeclass which contains the correct lookup function, based on the types of A and B - * @param macroGenerated a value created in the macro, to make it harder for users to use this API - */ - def _lookup[B, C]( - that: A => B - )( - implicit lookup: Lookupable[B], - macroGenerated: chisel3.internal.MacroGenerated - ): lookup.C = { - lookup.definitionLookup(that, this) - } - - /** @return the context of any Data's return from inside the instance */ - private[chisel3] def getInnerDataContext: Option[BaseModule] = proto match { - case value: BaseModule => - val newChild = Module.do_pseudo_apply(new internal.BaseModule.DefinitionClone(value))( - chisel3.internal.sourceinfo.UnlocatableSourceInfo, - chisel3.ExplicitCompileOptions.Strict - ) - newChild._circuit = value._circuit.orElse(Some(value)) - newChild._parent = None - Some(newChild) - case value: IsInstantiable => None - } - - override def toDefinition: Definition[A] = this - override def toInstance: Instance[A] = new Instance(underlying) - -} - -/** Factory methods for constructing [[Definition]]s */ -object Definition extends SourceInfoDoc { - implicit class DefinitionBaseModuleExtensions[T <: BaseModule](d: Definition[T]) { - - /** If this is an instance of a Module, returns the toTarget of this instance - * @return target of this instance - */ - def toTarget: ModuleTarget = d.proto.toTarget - - /** If this is an instance of a Module, returns the toAbsoluteTarget of this instance - * @return absoluteTarget of this instance - */ - def toAbsoluteTarget: IsModule = d.proto.toAbsoluteTarget - } - - /** A construction method to build a Definition of a Module - * - * @param proto the Module being defined - * - * @return the input module as a Definition - */ - def apply[T <: BaseModule with IsInstantiable](proto: => T): Definition[T] = macro DefinitionTransform.apply[T] - - /** A construction method to build a Definition of a Module - * - * @param bc the Module being defined - * - * @return the input module as a Definition - */ - def do_apply[T <: BaseModule with IsInstantiable]( - proto: => T - )( - implicit sourceInfo: SourceInfo, - compileOptions: CompileOptions - ): Definition[T] = { - val dynamicContext = { - val context = Builder.captureContext() - new DynamicContext(Nil, context.throwOnFirstError, context.warnReflectiveNaming, context.warningsAsErrors) - } - Builder.globalNamespace.copyTo(dynamicContext.globalNamespace) - dynamicContext.inDefinition = true - val (ir, module) = Builder.build(Module(proto), dynamicContext, false) - Builder.components ++= ir.components - Builder.annotations ++= ir.annotations - module._circuit = Builder.currentModule - dynamicContext.globalNamespace.copyTo(Builder.globalNamespace) - new Definition(Proto(module)) - } - -} - -/** Stores a [[Definition]] that is imported so that its Instances can be - * compiled separately. - */ -case class ImportDefinitionAnnotation[T <: BaseModule with IsInstantiable]( - definition: Definition[T], - overrideDefName: Option[String] = None) - extends NoTargetAnnotation diff --git a/core/src/main/scala/chisel3/experimental/hierarchy/Hierarchy.scala b/core/src/main/scala/chisel3/experimental/hierarchy/Hierarchy.scala deleted file mode 100644 index 2016bb54..00000000 --- a/core/src/main/scala/chisel3/experimental/hierarchy/Hierarchy.scala +++ /dev/null @@ -1,117 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 - -package chisel3.experimental.hierarchy - -import chisel3._ -import scala.collection.mutable.{HashMap, HashSet} -import scala.reflect.runtime.universe.TypeTag -import chisel3.internal.BaseModule.IsClone -import chisel3.experimental.BaseModule -import _root_.firrtl.annotations.IsModule -import scala.annotation.implicitNotFound - -/** Super-trait for Instance and Definition - * - * Enables writing functions which are Instance/Definition agnostic - */ -sealed trait Hierarchy[+A] { - private[chisel3] def underlying: Underlying[A] - private[chisel3] def proto: A = underlying match { - case Proto(value: A) => value - case Clone(i: IsClone[A]) => i.getProto - } - - /** Updated by calls to [[_lookup]], to avoid recloning returned Data's */ - private[chisel3] val cache = HashMap[Data, Data]() - private[chisel3] def getInnerDataContext: Option[BaseModule] - - /** Determine whether underlying proto is of type provided. - * - * @note IMPORTANT: this function requires summoning a TypeTag[B], which will fail if B is an inner class. - * @note IMPORTANT: this function IGNORES type parameters, akin to normal type erasure. - * @note IMPORTANT: this function relies on Java reflection for underlying proto, but Scala reflection for provided type - * - * E.g. isA[List[Int]] will return true, even if underlying proto is of type List[String] - * @return Whether underlying proto is of provided type (with caveats outlined above) - */ - def isA[B: TypeTag]: Boolean = { - val tptag = implicitly[TypeTag[B]] - // drop any type information for the comparison, because the proto will not have that information. - val name = tptag.tpe.toString.takeWhile(_ != '[') - inBaseClasses(name) - } - - // This code handles a special-case where, within an mdoc context, the type returned from - // scala reflection (typetag) looks different than when returned from java reflection. - // This function detects this case and reshapes the string to match. - private def modifyReplString(clz: String): String = { - if (clz != null) { - clz.split('.').toList match { - case "repl" :: "MdocSession" :: app :: rest => s"$app.this." + rest.mkString(".") - case other => clz - } - } else clz - } - private lazy val superClasses = calculateSuperClasses(proto.getClass()) - private def calculateSuperClasses(clz: Class[_]): Set[String] = { - if (clz != null) { - Set(modifyReplString(clz.getCanonicalName())) ++ - clz.getInterfaces().flatMap(i => calculateSuperClasses(i)) ++ - calculateSuperClasses(clz.getSuperclass()) - } else { - Set.empty[String] - } - } - private def inBaseClasses(clz: String): Boolean = superClasses.contains(clz) - - /** Used by Chisel's internal macros. DO NOT USE in your normal Chisel code!!! - * Instead, mark the field you are accessing with [[@public]] - * - * Given a selector function (that) which selects a member from the original, return the - * corresponding member from the hierarchy. - * - * Our @instantiable and @public macros generate the calls to this apply method - * - * By calling this function, we summon the proper Lookupable typeclass from our implicit scope. - * - * @param that a user-specified lookup function - * @param lookup typeclass which contains the correct lookup function, based on the types of A and B - * @param macroGenerated a value created in the macro, to make it harder for users to use this API - */ - def _lookup[B, C]( - that: A => B - )( - implicit lookup: Lookupable[B], - macroGenerated: chisel3.internal.MacroGenerated - ): lookup.C - - /** @return Return the underlying Definition[A] of this Hierarchy[A] */ - def toDefinition: Definition[A] - - /** @return Convert this Hierarchy[A] as a top-level Instance[A] */ - def toInstance: Instance[A] -} - -// Used to effectively seal Hierarchy, without requiring Definition and Instance to be in this file. -private[chisel3] trait SealedHierarchy[+A] extends Hierarchy[A] - -object Hierarchy { - implicit class HierarchyBaseModuleExtensions[T <: BaseModule](i: Hierarchy[T]) { - - /** Returns the toTarget of this hierarchy - * @return target of this hierarchy - */ - def toTarget: IsModule = i match { - case d: Definition[T] => new Definition.DefinitionBaseModuleExtensions(d).toTarget - case i: Instance[T] => new Instance.InstanceBaseModuleExtensions(i).toTarget - } - - /** Returns the toAbsoluteTarget of this hierarchy - * @return absoluteTarget of this Hierarchy - */ - def toAbsoluteTarget: IsModule = i match { - case d: Definition[T] => new Definition.DefinitionBaseModuleExtensions(d).toAbsoluteTarget - case i: Instance[T] => new Instance.InstanceBaseModuleExtensions(i).toAbsoluteTarget - } - } -} diff --git a/core/src/main/scala/chisel3/experimental/hierarchy/Instance.scala b/core/src/main/scala/chisel3/experimental/hierarchy/Instance.scala deleted file mode 100644 index 861023a1..00000000 --- a/core/src/main/scala/chisel3/experimental/hierarchy/Instance.scala +++ /dev/null @@ -1,148 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 - -package chisel3.experimental.hierarchy - -import scala.language.experimental.macros -import chisel3._ -import chisel3.internal.BaseModule.{InstantiableClone, IsClone, ModuleClone} -import chisel3.internal.Builder -import chisel3.internal.sourceinfo.{InstanceTransform, SourceInfo} -import chisel3.experimental.{BaseModule, ExtModule} -import chisel3.internal.firrtl.{Component, DefBlackBox, DefModule, Port} -import firrtl.annotations.IsModule -import chisel3.internal.throwException - -/** User-facing Instance type. - * Represents a unique instance of type [[A]] which are marked as @instantiable - * Can be created using Instance.apply method. - * - * @param underlying The internal representation of the instance, which may be either be directly the object, or a clone of an object - */ -final case class Instance[+A] private[chisel3] (private[chisel3] underlying: Underlying[A]) extends SealedHierarchy[A] { - underlying match { - case Proto(p: IsClone[_]) => chisel3.internal.throwException("Cannot have a Proto with a clone!") - case other => //Ok - } - - /** @return the context of any Data's return from inside the instance */ - private[chisel3] def getInnerDataContext: Option[BaseModule] = underlying match { - case Proto(value: BaseModule) => Some(value) - case Proto(value: IsInstantiable) => None - case Clone(i: BaseModule) => Some(i) - case Clone(i: InstantiableClone[_]) => i.getInnerContext - } - - /** @return the context this instance. Note that for non-module clones, getInnerDataContext will be the same as getClonedParent */ - private[chisel3] def getClonedParent: Option[BaseModule] = underlying match { - case Proto(value: BaseModule) => value._parent - case Clone(i: BaseModule) => i._parent - case Clone(i: InstantiableClone[_]) => i.getInnerContext - } - - /** Used by Chisel's internal macros. DO NOT USE in your normal Chisel code!!! - * Instead, mark the field you are accessing with [[@public]] - * - * Given a selector function (that) which selects a member from the original, return the - * corresponding member from the instance. - * - * Our @instantiable and @public macros generate the calls to this apply method - * - * By calling this function, we summon the proper Lookupable typeclass from our implicit scope. - * - * @param that a user-specified lookup function - * @param lookup typeclass which contains the correct lookup function, based on the types of A and B - * @param macroGenerated a value created in the macro, to make it harder for users to use this API - */ - def _lookup[B, C]( - that: A => B - )( - implicit lookup: Lookupable[B], - macroGenerated: chisel3.internal.MacroGenerated - ): lookup.C = { - lookup.instanceLookup(that, this) - } - - /** Returns the definition of this Instance */ - override def toDefinition: Definition[A] = new Definition(Proto(proto)) - override def toInstance: Instance[A] = this - -} - -/** Factory methods for constructing [[Instance]]s */ -object Instance extends SourceInfoDoc { - implicit class InstanceBaseModuleExtensions[T <: BaseModule](i: Instance[T]) { - - /** If this is an instance of a Module, returns the toTarget of this instance - * @return target of this instance - */ - def toTarget: IsModule = i.underlying match { - case Proto(x: BaseModule) => x.getTarget - case Clone(x: IsClone[_] with BaseModule) => x.getTarget - } - - /** If this is an instance of a Module, returns the toAbsoluteTarget of this instance - * @return absoluteTarget of this instance - */ - def toAbsoluteTarget: IsModule = i.underlying match { - case Proto(x) => x.toAbsoluteTarget - case Clone(x: IsClone[_] with BaseModule) => x.toAbsoluteTarget - } - - } - - /** A constructs an [[Instance]] from a [[Definition]] - * - * @param definition the Module being created - * @return an instance of the module definition - */ - def apply[T <: BaseModule with IsInstantiable](definition: Definition[T]): Instance[T] = - macro InstanceTransform.apply[T] - - /** A constructs an [[Instance]] from a [[Definition]] - * - * @param definition the Module being created - * @return an instance of the module definition - */ - def do_apply[T <: BaseModule with IsInstantiable]( - definition: Definition[T] - )( - implicit sourceInfo: SourceInfo, - compileOptions: CompileOptions - ): Instance[T] = { - // Check to see if the module is already defined internally or externally - val existingMod = Builder.components.map { - case c: DefModule if c.id == definition.proto => Some(c) - case c: DefBlackBox if c.name == definition.proto.name => Some(c) - case _ => None - }.flatten - - if (existingMod.isEmpty) { - // Add a Definition that will get emitted as an ExtModule so that FIRRTL - // does not complain about a missing element - val extModName = Builder.importDefinitionMap.getOrElse( - definition.proto.name, - throwException( - "Imported Definition information not found - possibly forgot to add ImportDefinition annotation?" - ) - ) - class EmptyExtModule extends ExtModule { - override def desiredName: String = extModName - override def generateComponent(): Option[Component] = { - require(!_closed, s"Can't generate $desiredName module more than once") - _closed = true - val firrtlPorts = definition.proto.getModulePorts.map { port => Port(port, port.specifiedDirection) } - val component = DefBlackBox(this, definition.proto.name, firrtlPorts, SpecifiedDirection.Unspecified, params) - Some(component) - } - } - Definition(new EmptyExtModule() {}) - } - - val ports = experimental.CloneModuleAsRecord(definition.proto) - val clone = ports._parent.get.asInstanceOf[ModuleClone[T]] - clone._madeFromDefinition = true - - new Instance(Clone(clone)) - } - -} diff --git a/core/src/main/scala/chisel3/experimental/hierarchy/IsInstantiable.scala b/core/src/main/scala/chisel3/experimental/hierarchy/IsInstantiable.scala deleted file mode 100644 index 27e06d92..00000000 --- a/core/src/main/scala/chisel3/experimental/hierarchy/IsInstantiable.scala +++ /dev/null @@ -1,16 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 - -package chisel3.experimental.hierarchy - -/** While this is public, it is not recommended for users to extend directly. - * Instead, use the [[@instantiable]] annotation on your trait or class. - * - * This trait indicates whether a class can be returned from an Instance. - */ -trait IsInstantiable - -object IsInstantiable { - implicit class IsInstantiableExtensions[T <: IsInstantiable](i: T) { - def toInstance: Instance[T] = new Instance(Proto(i)) - } -} diff --git a/core/src/main/scala/chisel3/experimental/hierarchy/IsLookupable.scala b/core/src/main/scala/chisel3/experimental/hierarchy/IsLookupable.scala deleted file mode 100644 index a82cbd7d..00000000 --- a/core/src/main/scala/chisel3/experimental/hierarchy/IsLookupable.scala +++ /dev/null @@ -1,25 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 - -package chisel3.experimental.hierarchy - -/** A User-extendable trait to mark metadata-containers, e.g. parameter case classes, as valid to return unchanged - * from an instance. - * - * This should only be true of the metadata returned is identical for ALL instances! - * - * @example For instances of the same proto, metadata or other construction parameters - * may be useful to access outside of the instance construction. For parameters that are - * the same for all instances, we should mark it as IsLookupable - * {{{ - * case class Params(debugMessage: String) extends IsLookupable - * class MyModule(p: Params) extends MultiIOModule { - * printf(p.debugMessage) - * } - * val myParams = Params("Hello World") - * val definition = Definition(new MyModule(myParams)) - * val i0 = Instance(definition) - * val i1 = Instance(definition) - * require(i0.p == i1.p) // p is only accessable because it extends IsLookupable - * }}} - */ -trait IsLookupable diff --git a/core/src/main/scala/chisel3/experimental/hierarchy/LibraryHooks.scala b/core/src/main/scala/chisel3/experimental/hierarchy/LibraryHooks.scala deleted file mode 100644 index d4818f63..00000000 --- a/core/src/main/scala/chisel3/experimental/hierarchy/LibraryHooks.scala +++ /dev/null @@ -1,34 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 - -package chisel3.experimental.hierarchy - -import scala.annotation.implicitNotFound - -@implicitNotFound("These functions are only for building hierarchy-compatible Chisel libraries! Users beware!") -// DO NOT extend unless you know what you are doing!!!!!! Not for the casual user! -trait InsideHierarchyLibraryExtension - -// Collection of public functions to give non-core-Chisel libraries the ability to build integrations with -// the experimental hierarchy package -object LibraryHooks { - - /** Builds a new instance given a definition and function to create a new instance-specific Underlying, from the - * definition's Underlying - * @note Implicitly requires being inside a Hierarchy Library Extension - */ - def buildInstance[A]( - definition: Definition[A], - createUnderlying: Underlying[A] => Underlying[A] - )( - implicit inside: InsideHierarchyLibraryExtension - ): Instance[A] = { - new Instance(createUnderlying(definition.underlying)) - } - - /** Builds a new definition given an Underlying implementation - * @note Implicitly requires being inside a Hierarchy Library Extension - */ - def buildDefinition[A](underlying: Underlying[A])(implicit inside: InsideHierarchyLibraryExtension): Definition[A] = { - new Definition(underlying) - } -} diff --git a/core/src/main/scala/chisel3/experimental/hierarchy/Lookupable.scala b/core/src/main/scala/chisel3/experimental/hierarchy/Lookupable.scala deleted file mode 100644 index aa35455d..00000000 --- a/core/src/main/scala/chisel3/experimental/hierarchy/Lookupable.scala +++ /dev/null @@ -1,511 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 - -package chisel3.experimental.hierarchy - -import chisel3.experimental.BaseModule -import chisel3.internal.sourceinfo.SourceInfo -import chisel3.internal.BaseModule.{InstanceClone, InstantiableClone, IsClone, ModuleClone} - -import scala.annotation.implicitNotFound -import scala.collection.mutable.HashMap -import chisel3._ -import chisel3.experimental.dataview.{isView, reify, reifySingleData} -import chisel3.internal.firrtl.{Arg, ILit, Index, ModuleIO, Slot, ULit} -import chisel3.internal.{throwException, AggregateViewBinding, Builder, ChildBinding, ViewBinding, ViewParent} - -/** Represents lookup typeclass to determine how a value accessed from an original IsInstantiable - * should be tweaked to return the Instance's version - * Sealed. - */ -@implicitNotFound( - "@public is only legal within a class or trait marked @instantiable, and only on vals of type" + - " Data, BaseModule, MemBase, IsInstantiable, IsLookupable, or Instance[_], or in an Iterable, Option, Either, or Tuple2" -) -trait Lookupable[-B] { - type C // Return type of the lookup - /** Function called to modify the returned value of type B from A, into C - * - * @param that function that selects B from A - * @param instance Instance of A, used to determine C's context - * @return - */ - def instanceLookup[A](that: A => B, instance: Instance[A]): C - - /** Function called to modify the returned value of type B from A, into C - * - * @param that function that selects B from A - * @param definition Definition of A, used to determine C's context - * @return - */ - def definitionLookup[A](that: A => B, definition: Definition[A]): C - protected def getProto[A](h: Hierarchy[A]): A = h.proto - protected def getUnderlying[A](h: Hierarchy[A]): Underlying[A] = h.underlying -} - -object Lookupable { - - /** Clones a data and sets its internal references to its parent module to be in a new context. - * - * @param data data to be cloned - * @param context new context - * @return - */ - private[chisel3] def cloneDataToContext[T <: Data]( - data: T, - context: BaseModule - )( - implicit sourceInfo: SourceInfo, - compileOptions: CompileOptions - ): T = { - internal.requireIsHardware(data, "cross module reference type") - data._parent match { - case None => data - case Some(parent) => - val newParent = cloneModuleToContext(Proto(parent), context) - newParent match { - case Proto(p) if p == parent => data - case Clone(m: BaseModule) => - val newChild = data.cloneTypeFull - newChild.setRef(data.getRef, true) - newChild.bind(internal.CrossModuleBinding) - newChild.setAllParents(Some(m)) - newChild - } - } - } - // The business logic of lookupData - // Also called by cloneViewToContext which potentially needs to lookup stuff from ioMap or the cache - private[chisel3] def doLookupData[A, B <: Data]( - data: B, - cache: HashMap[Data, Data], - ioMap: Option[Map[Data, Data]], - context: Option[BaseModule] - )( - implicit sourceInfo: SourceInfo, - compileOptions: CompileOptions - ): B = { - def impl[C <: Data](d: C): C = d match { - case x: Data if ioMap.nonEmpty && ioMap.get.contains(x) => ioMap.get(x).asInstanceOf[C] - case x: Data if cache.contains(x) => cache(x).asInstanceOf[C] - case _ => - assert(context.nonEmpty) // TODO is this even possible? Better error message here - val ret = cloneDataToContext(d, context.get) - cache(d) = ret - ret - } - data.binding match { - case Some(_: ChildBinding) => mapRootAndExtractSubField(data, impl) - case _ => impl(data) - } - } - - // Helper for co-iterating on Elements of aggregates, they must be the same type but that is unchecked - private def coiterate(a: Data, b: Data): Iterable[(Element, Element)] = { - val as = getRecursiveFields.lazily(a, "_") - val bs = getRecursiveFields.lazily(b, "_") - as.zip(bs).collect { case ((ae: Element, _), (be: Element, _)) => (ae, be) } - } - - /** Given a Data, find the root of its binding, apply a function to the root to get a "new root", - * and find the equivalent child Data in the "new root" - * - * @example {{{ - * Given `arg = a.b[2].c` and some `f`: - * 1. a = root(arg) = root(a.b[2].c) - * 2. newRoot = f(root(arg)) = f(a) - * 3. return newRoot.b[2].c - * }}} - * - * Invariants that elt is a Child of something of the type of data is dynamically checked as we traverse - */ - private def mapRootAndExtractSubField[A <: Data](arg: A, f: Data => Data): A = { - def err(msg: String) = throwException(s"Internal Error! $msg") - def unrollCoordinates(res: List[Arg], d: Data): (List[Arg], Data) = d.binding.get match { - case ChildBinding(parent) => - d.getRef match { - case arg @ (_: Slot | _: Index | _: ModuleIO) => unrollCoordinates(arg :: res, parent) - case other => err(s"unrollCoordinates failed for '$arg'! Unexpected arg '$other'") - } - case _ => (res, d) - } - def applyCoordinates(fullCoor: List[Arg], start: Data): Data = { - def rec(coor: List[Arg], d: Data): Data = { - if (coor.isEmpty) d - else { - val next = (coor.head, d) match { - case (Slot(_, name), rec: Record) => rec.elements(name) - case (Index(_, ILit(n)), vec: Vec[_]) => vec.apply(n.toInt) - case (ModuleIO(_, name), rec: Record) => rec.elements(name) - case (arg, _) => err(s"Unexpected Arg '$arg' applied to '$d'! Root was '$start'.") - } - applyCoordinates(coor.tail, next) - } - } - rec(fullCoor, start) - } - val (coor, root) = unrollCoordinates(Nil, arg) - val newRoot = f(root) - val result = applyCoordinates(coor, newRoot) - try { - result.asInstanceOf[A] - } catch { - case _: ClassCastException => err(s"Applying '$coor' to '$newRoot' somehow resulted in '$result'") - } - } - - // TODO this logic is complicated, can any of it be unified with viewAs? - // If `.viewAs` would capture its arguments, we could potentially use it - // TODO Describe what this is doing at a high level - private[chisel3] def cloneViewToContext[A, B <: Data]( - data: B, - cache: HashMap[Data, Data], - ioMap: Option[Map[Data, Data]], - context: Option[BaseModule] - )( - implicit sourceInfo: SourceInfo, - compileOptions: CompileOptions - ): B = { - // alias to shorten lookups - def lookupData[C <: Data](d: C) = doLookupData(d, cache, ioMap, context) - - val result = data.cloneTypeFull - - // We have to lookup the target(s) of the view since they may need to be underlying into the current context - val newBinding = data.topBinding match { - case ViewBinding(target) => ViewBinding(lookupData(reify(target))) - case avb @ AggregateViewBinding(map) => - data match { - case e: Element => ViewBinding(lookupData(reify(avb.lookup(e).get))) - case _: Aggregate => - // Provide a 1:1 mapping if possible - val singleTargetOpt = map.get(data).filter(_ => avb == data.binding.get).flatMap(reifySingleData) - singleTargetOpt match { - case Some(singleTarget) => // It is 1:1! - // This is a little tricky because the values in newMap need to point to Elements of newTarget - val newTarget = lookupData(singleTarget) - val newMap = coiterate(result, data).map { - case (res, from) => - (res: Data) -> mapRootAndExtractSubField(map(from), _ => newTarget) - }.toMap - AggregateViewBinding(newMap + (result -> newTarget)) - - case None => // No 1:1 mapping so we have to do a flat binding - // Just remap each Element of this aggregate - val newMap = coiterate(result, data).map { - // Upcast res to Data since Maps are invariant in the Key type parameter - case (res, from) => (res: Data) -> lookupData(reify(avb.lookup(from).get)) - }.toMap - AggregateViewBinding(newMap) - } - } - } - - // TODO Unify the following with `.viewAs` - // We must also mark non-1:1 and child Aggregates in the view for renaming - newBinding match { - case _: ViewBinding => // Do nothing - case AggregateViewBinding(childMap) => - if (!childMap.contains(result)) { - Builder.unnamedViews += result - } - // Binding does not capture 1:1 for child aggregates views - getRecursiveFields.lazily(result, "_").foreach { - case (agg: Aggregate, _) if agg != result => - Builder.unnamedViews += agg - case _ => // Do nothing - } - } - - result.bind(newBinding) - result.setAllParents(Some(ViewParent)) - result.forceName("view", Builder.viewNamespace) - result - } - - /** Given a module (either original or a clone), clone it to a new context - * - * This function effectively recurses up the parents of module to find whether: - * (1) A parent is already in the context; then we do nothing and return module - * (2) A parent is in a different clone of the context; then we clone all the parents up - * to that parent and set their parents to be in this underlying context - * (3) A parent has no root; in that case, we do nothing and return the module. - * - * @param module original or clone to be underlying into a new context - * @param context new context - * @return original or clone in the new context - */ - private[chisel3] def cloneModuleToContext[T <: BaseModule]( - module: Underlying[T], - context: BaseModule - )( - implicit sourceInfo: SourceInfo, - compileOptions: CompileOptions - ): Underlying[T] = { - // Recursive call - def rec[A <: BaseModule](m: A): Underlying[A] = { - def clone(x: A, p: Option[BaseModule], name: () => String): Underlying[A] = { - val newChild = Module.do_pseudo_apply(new internal.BaseModule.InstanceClone(x, name)) - newChild._parent = p - Clone(newChild) - } - (m, context) match { - case (c, ctx) if ctx == c => Proto(c) - case (c, ctx: IsClone[_]) if ctx.hasSameProto(c) => Clone(ctx.asInstanceOf[IsClone[A]]) - case (c, ctx) if c._parent.isEmpty => Proto(c) - case (_, _) => - cloneModuleToContext(Proto(m._parent.get), context) match { - case Proto(p) => Proto(m) - case Clone(p: BaseModule) => - clone(m, Some(p), () => m.instanceName) - } - } - } - module match { - case Proto(m) => rec(m) - case Clone(m: ModuleClone[_]) => - rec(m) match { - case Proto(mx) => Clone(mx) - case Clone(i: InstanceClone[_]) => - val newChild = Module.do_pseudo_apply(new InstanceClone(m.getProto, () => m.instanceName)) - newChild._parent = i._parent - Clone(newChild) - } - case Clone(m: InstanceClone[_]) => - rec(m) match { - case Proto(mx) => Clone(mx) - case Clone(i: InstanceClone[_]) => - val newChild = Module.do_pseudo_apply(new InstanceClone(m.getProto, () => m.instanceName)) - newChild._parent = i._parent - Clone(newChild) - } - } - } - - class SimpleLookupable[X] extends Lookupable[X] { - type B = X - type C = X - def definitionLookup[A](that: A => B, definition: Definition[A]): C = that(definition.proto) - def instanceLookup[A](that: A => B, instance: Instance[A]): C = that(instance.proto) - } - - implicit def lookupInstance[B <: BaseModule](implicit sourceInfo: SourceInfo, compileOptions: CompileOptions) = - new Lookupable[Instance[B]] { - type C = Instance[B] - def definitionLookup[A](that: A => Instance[B], definition: Definition[A]): C = { - val ret = that(definition.proto) - new Instance(cloneModuleToContext(ret.underlying, definition.getInnerDataContext.get)) - } - def instanceLookup[A](that: A => Instance[B], instance: Instance[A]): C = { - val ret = that(instance.proto) - instance.underlying match { - // If instance is just a normal module, no changing of context is necessary - case Proto(_) => new Instance(ret.underlying) - case Clone(_) => new Instance(cloneModuleToContext(ret.underlying, instance.getInnerDataContext.get)) - } - } - } - - implicit def lookupModule[B <: BaseModule](implicit sourceInfo: SourceInfo, compileOptions: CompileOptions) = - new Lookupable[B] { - type C = Instance[B] - def definitionLookup[A](that: A => B, definition: Definition[A]): C = { - val ret = that(definition.proto) - new Instance(cloneModuleToContext(Proto(ret), definition.getInnerDataContext.get)) - } - def instanceLookup[A](that: A => B, instance: Instance[A]): C = { - val ret = that(instance.proto) - instance.underlying match { - // If instance is just a normal module, no changing of context is necessary - case Proto(_) => new Instance(Proto(ret)) - case Clone(_) => new Instance(cloneModuleToContext(Proto(ret), instance.getInnerDataContext.get)) - } - } - } - - implicit def lookupData[B <: Data](implicit sourceInfo: SourceInfo, compileOptions: CompileOptions) = - new Lookupable[B] { - type C = B - def definitionLookup[A](that: A => B, definition: Definition[A]): C = { - val ret = that(definition.proto) - if (isView(ret)) { - ??? // TODO!!!!!! cloneViewToContext(ret, instance, ioMap, instance.getInnerDataContext) - } else { - doLookupData(ret, definition.cache, None, definition.getInnerDataContext) - } - } - def instanceLookup[A](that: A => B, instance: Instance[A]): C = { - val ret = that(instance.proto) - - def getIoMap(hierarchy: Hierarchy[_]): Option[Map[Data, Data]] = { - hierarchy.underlying match { - case Clone(x: ModuleClone[_]) => Some(x.ioMap) - case Proto(x: BaseModule) => Some(x.getChiselPorts.map { case (_, data) => data -> data }.toMap) - case Clone(x: InstantiableClone[_]) => getIoMap(x._innerContext) - case Clone(x: InstanceClone[_]) => None - case other => { - Builder.exception(s"Internal Error! Unexpected case where we can't get IO Map: $other") - } - } - } - val ioMap = getIoMap(instance) - - if (isView(ret)) { - cloneViewToContext(ret, instance.cache, ioMap, instance.getInnerDataContext) - } else { - doLookupData(ret, instance.cache, ioMap, instance.getInnerDataContext) - } - - } - } - - private[chisel3] def cloneMemToContext[T <: MemBase[_]]( - mem: T, - context: BaseModule - )( - implicit sourceInfo: SourceInfo, - compileOptions: CompileOptions - ): T = { - mem._parent match { - case None => mem - case Some(parent) => - val newParent = cloneModuleToContext(Proto(parent), context) - newParent match { - case Proto(p) if p == parent => mem - case Clone(mod: BaseModule) => - val existingMod = Builder.currentModule - Builder.currentModule = Some(mod) - val newChild: T = mem match { - case m: Mem[_] => new Mem(m.t.asInstanceOf[Data].cloneTypeFull, m.length).asInstanceOf[T] - case m: SyncReadMem[_] => - new SyncReadMem(m.t.asInstanceOf[Data].cloneTypeFull, m.length, m.readUnderWrite).asInstanceOf[T] - } - Builder.currentModule = existingMod - newChild.setRef(mem.getRef, true) - newChild - } - } - } - - implicit def lookupMem[B <: MemBase[_]](implicit sourceInfo: SourceInfo, compileOptions: CompileOptions) = - new Lookupable[B] { - type C = B - def definitionLookup[A](that: A => B, definition: Definition[A]): C = { - cloneMemToContext(that(definition.proto), definition.getInnerDataContext.get) - } - def instanceLookup[A](that: A => B, instance: Instance[A]): C = { - cloneMemToContext(that(instance.proto), instance.getInnerDataContext.get) - } - } - - import scala.language.higherKinds // Required to avoid warning for lookupIterable type parameter - implicit def lookupIterable[B, F[_] <: Iterable[_]]( - implicit sourceInfo: SourceInfo, - compileOptions: CompileOptions, - lookupable: Lookupable[B] - ) = new Lookupable[F[B]] { - type C = F[lookupable.C] - def definitionLookup[A](that: A => F[B], definition: Definition[A]): C = { - val ret = that(definition.proto).asInstanceOf[Iterable[B]] - ret.map { x: B => lookupable.definitionLookup[A](_ => x, definition) }.asInstanceOf[C] - } - def instanceLookup[A](that: A => F[B], instance: Instance[A]): C = { - import instance._ - val ret = that(proto).asInstanceOf[Iterable[B]] - ret.map { x: B => lookupable.instanceLookup[A](_ => x, instance) }.asInstanceOf[C] - } - } - implicit def lookupOption[B]( - implicit sourceInfo: SourceInfo, - compileOptions: CompileOptions, - lookupable: Lookupable[B] - ) = new Lookupable[Option[B]] { - type C = Option[lookupable.C] - def definitionLookup[A](that: A => Option[B], definition: Definition[A]): C = { - val ret = that(definition.proto) - ret.map { x: B => lookupable.definitionLookup[A](_ => x, definition) } - } - def instanceLookup[A](that: A => Option[B], instance: Instance[A]): C = { - import instance._ - val ret = that(proto) - ret.map { x: B => lookupable.instanceLookup[A](_ => x, instance) } - } - } - implicit def lookupEither[L, R]( - implicit sourceInfo: SourceInfo, - compileOptions: CompileOptions, - lookupableL: Lookupable[L], - lookupableR: Lookupable[R] - ) = new Lookupable[Either[L, R]] { - type C = Either[lookupableL.C, lookupableR.C] - def definitionLookup[A](that: A => Either[L, R], definition: Definition[A]): C = { - val ret = that(definition.proto) - ret.map { x: R => lookupableR.definitionLookup[A](_ => x, definition) }.left.map { x: L => - lookupableL.definitionLookup[A](_ => x, definition) - } - } - def instanceLookup[A](that: A => Either[L, R], instance: Instance[A]): C = { - import instance._ - val ret = that(proto) - ret.map { x: R => lookupableR.instanceLookup[A](_ => x, instance) }.left.map { x: L => - lookupableL.instanceLookup[A](_ => x, instance) - } - } - } - - implicit def lookupTuple2[X, Y]( - implicit sourceInfo: SourceInfo, - compileOptions: CompileOptions, - lookupableX: Lookupable[X], - lookupableY: Lookupable[Y] - ) = new Lookupable[(X, Y)] { - type C = (lookupableX.C, lookupableY.C) - def definitionLookup[A](that: A => (X, Y), definition: Definition[A]): C = { - val ret = that(definition.proto) - ( - lookupableX.definitionLookup[A](_ => ret._1, definition), - lookupableY.definitionLookup[A](_ => ret._2, definition) - ) - } - def instanceLookup[A](that: A => (X, Y), instance: Instance[A]): C = { - import instance._ - val ret = that(proto) - (lookupableX.instanceLookup[A](_ => ret._1, instance), lookupableY.instanceLookup[A](_ => ret._2, instance)) - } - } - - implicit def lookupIsInstantiable[B <: IsInstantiable]( - implicit sourceInfo: SourceInfo, - compileOptions: CompileOptions - ) = new Lookupable[B] { - type C = Instance[B] - def definitionLookup[A](that: A => B, definition: Definition[A]): C = { - val ret = that(definition.proto) - val underlying = new InstantiableClone[B] { - val getProto = ret - lazy val _innerContext = definition - } - new Instance(Clone(underlying)) - } - def instanceLookup[A](that: A => B, instance: Instance[A]): C = { - val ret = that(instance.proto) - val underlying = new InstantiableClone[B] { - val getProto = ret - lazy val _innerContext = instance - } - new Instance(Clone(underlying)) - } - } - - implicit def lookupIsLookupable[B <: IsLookupable](implicit sourceInfo: SourceInfo, compileOptions: CompileOptions) = - new SimpleLookupable[B]() - - implicit val lookupInt = new SimpleLookupable[Int]() - implicit val lookupByte = new SimpleLookupable[Byte]() - implicit val lookupShort = new SimpleLookupable[Short]() - implicit val lookupLong = new SimpleLookupable[Long]() - implicit val lookupFloat = new SimpleLookupable[Float]() - implicit val lookupChar = new SimpleLookupable[Char]() - implicit val lookupString = new SimpleLookupable[String]() - implicit val lookupBoolean = new SimpleLookupable[Boolean]() - implicit val lookupBigInt = new SimpleLookupable[BigInt]() -} diff --git a/core/src/main/scala/chisel3/experimental/hierarchy/Underlying.scala b/core/src/main/scala/chisel3/experimental/hierarchy/Underlying.scala deleted file mode 100644 index 864cc8af..00000000 --- a/core/src/main/scala/chisel3/experimental/hierarchy/Underlying.scala +++ /dev/null @@ -1,14 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 - -package chisel3.experimental.hierarchy - -import chisel3.internal.BaseModule.IsClone - -/** Represents the underlying implementation of a Definition or Instance */ -sealed trait Underlying[+T] - -/** A clone of a real implementation */ -final case class Clone[+T](isClone: IsClone[T]) extends Underlying[T] - -/** An actual implementation */ -final case class Proto[+T](proto: T) extends Underlying[T] diff --git a/core/src/main/scala/chisel3/experimental/hierarchy/package.scala b/core/src/main/scala/chisel3/experimental/hierarchy/package.scala deleted file mode 100644 index c309ab52..00000000 --- a/core/src/main/scala/chisel3/experimental/hierarchy/package.scala +++ /dev/null @@ -1,48 +0,0 @@ -package chisel3.experimental - -package object hierarchy { - - /** Classes or traits which will be used with the [[Definition]] + [[Instance]] api should be marked - * with the [[@instantiable]] annotation at the class/trait definition. - * - * @example {{{ - * @instantiable - * class MyModule extends Module { - * ... - * } - * - * val d = Definition(new MyModule) - * val i0 = Instance(d) - * val i1 = Instance(d) - * }}} - */ - class instantiable extends chisel3.internal.instantiable - - /** Classes marked with [[@instantiable]] can have their vals marked with the [[@public]] annotation to - * enable accessing these values from a [[Definition]] or [[Instance]] of the class. - * - * Only vals of the the following types can be marked [[@public]]: - * 1. IsInstantiable - * 2. IsLookupable - * 3. Data - * 4. BaseModule - * 5. Iterable/Option containing a type that meets these requirements - * 6. Basic type like String, Int, BigInt etc. - * - * @example {{{ - * @instantiable - * class MyModule extends Module { - * @public val in = IO(Input(UInt(3.W))) - * @public val out = IO(Output(UInt(3.W))) - * .. - * } - * - * val d = Definition(new MyModule) - * val i0 = Instance(d) - * val i1 = Instance(d) - * - * i1.in := i0.out - * }}} - */ - class public extends chisel3.internal.public -} diff --git a/core/src/main/scala/chisel3/experimental/package.scala b/core/src/main/scala/chisel3/experimental/package.scala index 2b493aab..a69c5b6e 100644 --- a/core/src/main/scala/chisel3/experimental/package.scala +++ b/core/src/main/scala/chisel3/experimental/package.scala @@ -15,91 +15,16 @@ package object experimental { 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) - @deprecated("This type has moved to chisel3", "Chisel 3.5") type ChiselEnum = EnumFactory // 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 = { - BaseModule.cloneIORecord(proto) - } - } - val requireIsHardware = chisel3.internal.requireIsHardware val requireIsChiselType = chisel3.internal.requireIsChiselType type Direction = ActualDirection val Direction = ActualDirection - /** The same as [[IO]] except there is no prefix for the name of the val */ - def FlatIO[T <: Record](gen: => T)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): T = noPrefix { - import dataview._ - def coerceDirection(d: Data) = { - import chisel3.{SpecifiedDirection => SD} - DataMirror.specifiedDirectionOf(gen) match { - case SD.Flip => Flipped(d) - case SD.Input => Input(d) - case SD.Output => Output(d) - case _ => d - } - } - val ports: Seq[Data] = - gen.elements.toSeq.reverse.map { - case (name, data) => - val p = chisel3.IO(coerceDirection(chiselTypeClone(data).asInstanceOf[Data])) - p.suggestName(name) - p - - } - - implicit val dv: DataView[Seq[Data], T] = DataView.mapping( - _ => chiselTypeClone(gen).asInstanceOf[T], - (seq, rec) => seq.zip(rec.elements.toSeq.reverse).map { case (port, (_, field)) => port -> field } - ) - ports.viewAs[T] - } - - 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 class treedump extends chisel3.internal.naming.treedump -- cgit v1.2.3