diff options
| author | Jack | 2021-12-18 08:27:38 +0000 |
|---|---|---|
| committer | Jack | 2021-12-18 08:27:38 +0000 |
| commit | dd9ad534771247ac16eaa47eb9794102736b5102 (patch) | |
| tree | d4566d317cb8526b79017de1e438aea8217dd1d4 /core/src/main/scala/chisel3/experimental | |
| parent | 440edc4436fb3a8a4175ae425a0d31c4997ee60f (diff) | |
| parent | f50f74f583fba7b98e550c440df091e559ce32b8 (diff) | |
Merge branch 'master' into 3.5-release
Diffstat (limited to 'core/src/main/scala/chisel3/experimental')
13 files changed, 942 insertions, 166 deletions
diff --git a/core/src/main/scala/chisel3/experimental/Analog.scala b/core/src/main/scala/chisel3/experimental/Analog.scala index 6cca81f5..e94bae2d 100644 --- a/core/src/main/scala/chisel3/experimental/Analog.scala +++ b/core/src/main/scala/chisel3/experimental/Analog.scala @@ -27,9 +27,7 @@ import scala.collection.mutable 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" - } + override def toString: String = stringAccessor(s"Analog$width") private[chisel3] override def typeEquivalent(that: Data): Boolean = that.isInstanceOf[Analog] && this.width == that.width diff --git a/core/src/main/scala/chisel3/experimental/Trace.scala b/core/src/main/scala/chisel3/experimental/Trace.scala new file mode 100644 index 00000000..2d965c7b --- /dev/null +++ b/core/src/main/scala/chisel3/experimental/Trace.scala @@ -0,0 +1,69 @@ +package chisel3.experimental + +import chisel3.internal.HasId +import chisel3.{Aggregate, Data, Element, Module} +import firrtl.AnnotationSeq +import firrtl.annotations.{Annotation, CompleteTarget, SingleTargetAnnotation} +import firrtl.transforms.DontTouchAllTargets + +/** The util that records the reference map from original [[Data]]/[[Module]] annotated in Chisel and final FIRRTL. + * @example + * {{{ + * class Dut extends Module { + * val a = WireDefault(Bool()) + * Trace.traceName(a) + * } + * val annos = (new ChiselStage).execute(Seq(ChiselGeneratorAnnotation(() => new Dut))) + * val dut = annos.collectFirst { case DesignAnnotation(dut) => dut }.get.asInstanceOf[CollideModule] + * // get final reference of `a` Seq(ReferenceTarget("Dut", "Dut", Seq.empty, "a", Seq.empty)) + * val firrtlReferenceOfDutA = finalTarget(annos)(dut.a) + * }}} + * */ +object Trace { + + /** Trace a Instance name. */ + def traceName(x: Module): Unit = { + annotate(new ChiselAnnotation { + def toFirrtl: Annotation = TraceNameAnnotation(x.toAbsoluteTarget, x.toAbsoluteTarget) + }) + } + + /** Trace a Data name. */ + def traceName(x: Data): Unit = { + x match { + case aggregate: Aggregate => + annotate(new ChiselAnnotation { + def toFirrtl: Annotation = TraceNameAnnotation(aggregate.toAbsoluteTarget, aggregate.toAbsoluteTarget) + }) + aggregate.getElements.foreach(traceName) + case element: Element => + annotate(new ChiselAnnotation { + def toFirrtl: Annotation = TraceNameAnnotation(element.toAbsoluteTarget, element.toAbsoluteTarget) + }) + } + } + + /** An Annotation that records the original target annotate from Chisel. + * + * @param target target that should be renamed by [[firrtl.RenameMap]] in the firrtl transforms. + * @param chiselTarget original annotated target in Chisel, which should not be changed or renamed in FIRRTL. + */ + private case class TraceNameAnnotation[T <: CompleteTarget](target: T, chiselTarget: T) + extends SingleTargetAnnotation[T] + with DontTouchAllTargets { + def duplicate(n: T): Annotation = this.copy(target = n) + } + + /** Get [[CompleteTarget]] of the target `x` for `annos`. + * This API can be used to find the final reference to a signal or module which is marked by `traceName` + */ + def finalTarget(annos: AnnotationSeq)(x: HasId): Seq[CompleteTarget] = finalTargetMap(annos) + .getOrElse(x.toAbsoluteTarget, Seq.empty) + + /** Get all traced signal/module for `annos` + * This API can be used to gather all final reference to the signal or module which is marked by `traceName` + */ + def finalTargetMap(annos: AnnotationSeq): Map[CompleteTarget, Seq[CompleteTarget]] = annos.collect { + case TraceNameAnnotation(t, chiselTarget) => chiselTarget -> t + }.groupBy(_._1).map{case (k, v) => k -> v.map(_._2)} +} diff --git a/core/src/main/scala/chisel3/experimental/dataview/DataProduct.scala b/core/src/main/scala/chisel3/experimental/dataview/DataProduct.scala index 55dd8505..438f97b8 100644 --- a/core/src/main/scala/chisel3/experimental/dataview/DataProduct.scala +++ b/core/src/main/scala/chisel3/experimental/dataview/DataProduct.scala @@ -3,7 +3,7 @@ package chisel3.experimental.dataview import chisel3.experimental.BaseModule -import chisel3.{Data, getRecursiveFields} +import chisel3.{Data, Vec, getRecursiveFields} import scala.annotation.implicitNotFound @@ -41,17 +41,24 @@ trait DataProduct[-A] { def dataSet(a: A): Data => Boolean = dataIterator(a, "").map(_._1).toSet } -/** Encapsulating object for automatically provided implementations of [[DataProduct]] +/** Low priority built-in implementations of [[DataProduct]] * - * @note DataProduct implementations provided in this object are available in the implicit scope + * @note This trait exists so that `dataDataProduct` can be lower priority than `seqDataProduct` to resolve ambiguity */ -object DataProduct { +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)] = { @@ -69,4 +76,237 @@ object DataProduct { 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 index caf004c2..c17a5574 100644 --- a/core/src/main/scala/chisel3/experimental/dataview/DataView.scala +++ b/core/src/main/scala/chisel3/experimental/dataview/DataView.scala @@ -3,9 +3,12 @@ package chisel3.experimental.dataview import chisel3._ -import chisel3.internal.sourceinfo.SourceInfo -import scala.reflect.runtime.universe.WeakTypeTag +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 @@ -132,9 +135,241 @@ object DataView { 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 */ diff --git a/core/src/main/scala/chisel3/experimental/hierarchy/Definition.scala b/core/src/main/scala/chisel3/experimental/hierarchy/Definition.scala index 0cc3d131..c7b51072 100644 --- a/core/src/main/scala/chisel3/experimental/hierarchy/Definition.scala +++ b/core/src/main/scala/chisel3/experimental/hierarchy/Definition.scala @@ -18,13 +18,9 @@ import firrtl.annotations.{IsModule, ModuleTarget} * * These definitions are then used to create multiple [[Instance]]s. * - * @param cloned The internal representation of the instance, which may be either be directly the object, or a clone of an object + * @param underlying The internal representation of the definition, which may be either be directly the object, or a clone of an object */ -case class Definition[+A] private[chisel3] (private[chisel3] cloned: Either[A, IsClone[A]]) extends IsLookupable { - private[chisel3] def proto: A = cloned match { - case Left(value: A) => value - case Right(i: IsClone[A]) => i._proto - } +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]] * @@ -43,20 +39,20 @@ case class Definition[+A] private[chisel3] (private[chisel3] cloned: Either[A, I lookup.definitionLookup(that, this) } - /** Updated by calls to [[apply]], to avoid recloning returned Data's */ - private [chisel3] val cache = HashMap[Data, Data]() - - /** @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_apply(new internal.BaseModule.DefinitionClone(value))(chisel3.internal.sourceinfo.UnlocatableSourceInfo, chisel3.ExplicitCompileOptions.Strict) + 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 */ @@ -90,11 +86,12 @@ object Definition extends SourceInfoDoc { val dynamicContext = new DynamicContext(Nil) Builder.globalNamespace.copyTo(dynamicContext.globalNamespace) dynamicContext.inDefinition = true - val (ir, module) = Builder.build(Module(proto), dynamicContext) + 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(Left(module)) + new Definition(Proto(module)) } + } diff --git a/core/src/main/scala/chisel3/experimental/hierarchy/Hierarchy.scala b/core/src/main/scala/chisel3/experimental/hierarchy/Hierarchy.scala new file mode 100644 index 00000000..503e437b --- /dev/null +++ b/core/src/main/scala/chisel3/experimental/hierarchy/Hierarchy.scala @@ -0,0 +1,112 @@ +// 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]] + val name = tptag.tpe.toString + 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 index 9b17bfce..97b62c23 100644 --- a/core/src/main/scala/chisel3/experimental/hierarchy/Instance.scala +++ b/core/src/main/scala/chisel3/experimental/hierarchy/Instance.scala @@ -14,38 +14,29 @@ import firrtl.annotations.IsModule * Represents a unique instance of type [[A]] which are marked as @instantiable * Can be created using Instance.apply method. * - * @param cloned The internal representation of the instance, which may be either be directly the object, or a clone of an object + * @param underlying The internal representation of the instance, which may be either be directly the object, or a clone of an object */ -case class Instance[+A] private [chisel3] (private[chisel3] cloned: Either[A, IsClone[A]]) { - - /** Returns the original object which is instantiated here. - * If this is an instance of a clone, return that clone's original proto - * - * @return the original object which was instantiated - */ - private[chisel3] def proto: A = cloned match { - case Left(value: A) => value - case Right(i: IsClone[A]) => i._proto +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] = cloned match { - case Left(value: BaseModule) => Some(value) - case Left(value: IsInstantiable) => None - case Right(i: BaseModule) => Some(i) - case Right(i: InstantiableClone[_]) => i._parent + 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] = cloned match { - case Left(value: BaseModule) => value._parent - case Right(i: BaseModule) => i._parent - case Right(i: InstantiableClone[_]) => i._parent + 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 } - /** Updated by calls to [[apply]], to avoid recloning returned Data's */ - private [chisel3] val cache = HashMap[Data, Data]() - /** Used by Chisel's internal macros. DO NOT USE in your normal Chisel code!!! * Instead, mark the field you are accessing with [[@public]] * @@ -65,7 +56,8 @@ case class Instance[+A] private [chisel3] (private[chisel3] cloned: Either[A, Is } /** Returns the definition of this Instance */ - def toDefinition: Definition[A] = new Definition(Left(proto)) + override def toDefinition: Definition[A] = new Definition(Proto(proto)) + override def toInstance: Instance[A] = this } @@ -75,17 +67,17 @@ object Instance extends SourceInfoDoc { /** If this is an instance of a Module, returns the toTarget of this instance * @return target of this instance */ - def toTarget: IsModule = i.cloned match { - case Left(x: BaseModule) => x.getTarget - case Right(x: IsClone[_] with BaseModule) => x.getTarget + 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.cloned match { - case Left(x) => x.toAbsoluteTarget - case Right(x: IsClone[_] with BaseModule) => x.toAbsoluteTarget + def toAbsoluteTarget: IsModule = i.underlying match { + case Proto(x) => x.toAbsoluteTarget + case Clone(x: IsClone[_] with BaseModule) => x.toAbsoluteTarget } } @@ -105,7 +97,7 @@ object Instance extends SourceInfoDoc { val ports = experimental.CloneModuleAsRecord(definition.proto) val clone = ports._parent.get.asInstanceOf[ModuleClone[T]] clone._madeFromDefinition = true - new Instance(Right(clone)) + 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 index 26ba0286..4f3c2d42 100644 --- a/core/src/main/scala/chisel3/experimental/hierarchy/IsInstantiable.scala +++ b/core/src/main/scala/chisel3/experimental/hierarchy/IsInstantiable.scala @@ -12,6 +12,6 @@ trait IsInstantiable object IsInstantiable { implicit class IsInstantiableExtensions[T <: IsInstantiable](i: T) { - def toInstance: Instance[T] = new Instance(Left(i)) + def toInstance: Instance[T] = new Instance(Proto(i)) } } diff --git a/core/src/main/scala/chisel3/experimental/hierarchy/LibraryHooks.scala b/core/src/main/scala/chisel3/experimental/hierarchy/LibraryHooks.scala new file mode 100644 index 00000000..c16cc633 --- /dev/null +++ b/core/src/main/scala/chisel3/experimental/hierarchy/LibraryHooks.scala @@ -0,0 +1,31 @@ +// 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 index b9617723..ff4d676c 100644 --- a/core/src/main/scala/chisel3/experimental/hierarchy/Lookupable.scala +++ b/core/src/main/scala/chisel3/experimental/hierarchy/Lookupable.scala @@ -19,7 +19,7 @@ import chisel3.internal.{AggregateViewBinding, Builder, ChildBinding, ViewBindin */ @implicitNotFound("@public is only legal within a class marked @instantiable and only on vals of type" + " Data, BaseModule, IsInstantiable, IsLookupable, or Instance[_], or in an Iterable or Option") -sealed trait Lookupable[-B] { +trait Lookupable[-B] { type C // Return type of the lookup /** Function called to modify the returned value of type B from A, into C * @@ -36,9 +36,11 @@ sealed trait Lookupable[-B] { * @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 } -private[chisel3] object Lookupable { +object Lookupable { /** Clones a data and sets its internal references to its parent module to be in a new context. * @@ -52,10 +54,10 @@ private[chisel3] object Lookupable { data._parent match { case None => data case Some(parent) => - val newParent = cloneModuleToContext(Left(parent), context) + val newParent = cloneModuleToContext(Proto(parent), context) newParent match { - case Left(p) if p == parent => data - case Right(m: BaseModule) => + case Proto(p) if p == parent => data + case Clone(m: BaseModule) => val newChild = data.cloneTypeFull newChild.setRef(data.getRef, true) newChild.bind(internal.CrossModuleBinding) @@ -145,7 +147,7 @@ private[chisel3] object Lookupable { val result = data.cloneTypeFull - // We have to lookup the target(s) of the view since they may need to be cloned into the current context + // 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, targetOpt) => data match { @@ -199,51 +201,51 @@ private[chisel3] object Lookupable { * 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 cloned context + * 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 cloned into a new context + * @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: Either[T, IsClone[T]], context: BaseModule) - (implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Either[T, IsClone[T]] = { + 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): Either[A, IsClone[A]] = { - def clone(x: A, p: Option[BaseModule], name: () => String): Either[A, IsClone[A]] = { - val newChild = Module.do_apply(new internal.BaseModule.InstanceClone(x, name)) + 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 - Right(newChild) + Clone(newChild) } (m, context) match { - case (c, ctx) if ctx == c => Left(c) - case (c, ctx: IsClone[_]) if ctx.isACloneOf(c) => Right(ctx.asInstanceOf[IsClone[A]]) - case (c, ctx) if c._parent.isEmpty => Left(c) + 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(Left(m._parent.get), context) match { - case Left(p) => Left(m) - case Right(p: BaseModule) => + 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 Left(m) => rec(m) - case Right(m: ModuleClone[_]) => + case Proto(m) => rec(m) + case Clone(m: ModuleClone[_]) => rec(m) match { - case Left(mx) => Right(mx) - case Right(i: InstanceClone[_]) => - val newChild = Module.do_apply(new InstanceClone(m._proto, () => m.instanceName)) + 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 - Right(newChild) + Clone(newChild) } - case Right(m: InstanceClone[_]) => + case Clone(m: InstanceClone[_]) => rec(m) match { - case Left(mx) => Right(mx) - case Right(i: InstanceClone[_]) => - val newChild = Module.do_apply(new InstanceClone(m._proto, () => m.instanceName)) + 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 - Right(newChild) + Clone(newChild) } } } @@ -259,14 +261,14 @@ private[chisel3] object Lookupable { type C = Instance[B] def definitionLookup[A](that: A => Instance[B], definition: Definition[A]): C = { val ret = that(definition.proto) - new Instance(cloneModuleToContext(ret.cloned, definition.getInnerDataContext.get)) + 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.cloned match { + instance.underlying match { // If instance is just a normal module, no changing of context is necessary - case Left(_) => new Instance(ret.cloned) - case Right(_) => new Instance(cloneModuleToContext(ret.cloned, instance.getInnerDataContext.get)) + case Proto(_) => new Instance(ret.underlying) + case Clone(_) => new Instance(cloneModuleToContext(ret.underlying, instance.getInnerDataContext.get)) } } } @@ -275,14 +277,14 @@ private[chisel3] object Lookupable { type C = Instance[B] def definitionLookup[A](that: A => B, definition: Definition[A]): C = { val ret = that(definition.proto) - new Instance(cloneModuleToContext(Left(ret), definition.getInnerDataContext.get)) + new Instance(cloneModuleToContext(Proto(ret), definition.getInnerDataContext.get)) } def instanceLookup[A](that: A => B, instance: Instance[A]): C = { val ret = that(instance.proto) - instance.cloned match { + instance.underlying match { // If instance is just a normal module, no changing of context is necessary - case Left(_) => new Instance(Left(ret)) - case Right(_) => new Instance(cloneModuleToContext(Left(ret), instance.getInnerDataContext.get)) + case Proto(_) => new Instance(Proto(ret)) + case Clone(_) => new Instance(cloneModuleToContext(Proto(ret), instance.getInnerDataContext.get)) } } } @@ -299,9 +301,9 @@ private[chisel3] object Lookupable { } def instanceLookup[A](that: A => B, instance: Instance[A]): C = { val ret = that(instance.proto) - val ioMap: Option[Map[Data, Data]] = instance.cloned match { - case Right(x: ModuleClone[_]) => Some(x.ioMap) - case Left(x: BaseModule) => Some(x.getChiselPorts.map { case (_, data) => data -> data }.toMap) + val ioMap: Option[Map[Data, Data]] = instance.underlying match { + case Clone(x: ModuleClone[_]) => Some(x.ioMap) + case Proto(x: BaseModule) => Some(x.getChiselPorts.map { case (_, data) => data -> data }.toMap) case _ => None } if (isView(ret)) { @@ -342,15 +344,19 @@ private[chisel3] object Lookupable { type C = Instance[B] def definitionLookup[A](that: A => B, definition: Definition[A]): C = { val ret = that(definition.proto) - val cloned = new InstantiableClone(ret) - cloned._parent = definition.getInnerDataContext - new Instance(Right(cloned)) + 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 cloned = new InstantiableClone(ret) - cloned._parent = instance.getInnerDataContext - new Instance(Right(cloned)) + val underlying = new InstantiableClone[B] { + val getProto = ret + lazy val _innerContext = instance + } + new Instance(Clone(underlying)) } } diff --git a/core/src/main/scala/chisel3/experimental/hierarchy/Underlying.scala b/core/src/main/scala/chisel3/experimental/hierarchy/Underlying.scala new file mode 100644 index 00000000..864cc8af --- /dev/null +++ b/core/src/main/scala/chisel3/experimental/hierarchy/Underlying.scala @@ -0,0 +1,14 @@ +// 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/package.scala b/core/src/main/scala/chisel3/experimental/package.scala index 8018159f..5397a1c3 100644 --- a/core/src/main/scala/chisel3/experimental/package.scala +++ b/core/src/main/scala/chisel3/experimental/package.scala @@ -2,7 +2,8 @@ package chisel3 -import chisel3.internal.NamedComponent +import chisel3.ExplicitCompileOptions.Strict +import chisel3.experimental.DataMirror.internal.chiselTypeClone import chisel3.internal.sourceinfo.SourceInfo /** Package for experimental features, which may have their API changed, be removed, etc. @@ -167,8 +168,149 @@ package object experimental { // Use to remove prefixes not in provided scope val noPrefix = chisel3.internal.noPrefix - /** Base simulation-only component. */ - abstract class BaseSim extends NamedComponent { - _parent.foreach(_.addId(this)) + // ****************************** Hardware equivalents of Scala Tuples ****************************** + // These are intended to be used via DataView + + /** [[Data]] equivalent of Scala's [[Tuple2]] + * + * Users may not instantiate this class directly. Instead they should use the implicit conversion from `Tuple2` in + * `chisel3.experimental.conversions` + */ + final class HWTuple2[+A <: Data, +B <: Data] private[chisel3] (val _1: A, val _2: B) extends Bundle()(Strict) { + // Because this implementation exists in chisel3.core, it cannot compile with the plugin, so we implement the behavior manually + override protected def _usingPlugin: Boolean = true + override protected def _cloneTypeImpl: Bundle = new HWTuple2(chiselTypeClone(_1), chiselTypeClone(_2)) + } + + /** [[Data]] equivalent of Scala's [[Tuple3]] + * + * Users may not instantiate this class directly. Instead they should use the implicit conversion from `Tuple3` in + * `chisel3.experimental.conversions` + */ + final class HWTuple3[+A <: Data, +B <: Data, +C <: Data] private[chisel3] ( + val _1: A, val _2: B, val _3: C + ) extends Bundle()(Strict) { + // Because this implementation exists in chisel3.core, it cannot compile with the plugin, so we implement the behavior manually + override protected def _usingPlugin: Boolean = true + override protected def _cloneTypeImpl: Bundle = new HWTuple3( + chiselTypeClone(_1), chiselTypeClone(_2), chiselTypeClone(_3) + ) + } + + /** [[Data]] equivalent of Scala's [[Tuple4]] + * + * Users may not instantiate this class directly. Instead they should use the implicit conversion from `Tuple4` in + * `chisel3.experimental.conversions` + */ + final class HWTuple4[+A <: Data, +B <: Data, +C <: Data, +D <: Data] private[chisel3] ( + val _1: A, val _2: B, val _3: C, val _4: D + ) extends Bundle()(Strict) { + // Because this implementation exists in chisel3.core, it cannot compile with the plugin, so we implement the behavior manually + override protected def _usingPlugin: Boolean = true + override protected def _cloneTypeImpl: Bundle = new HWTuple4( + chiselTypeClone(_1), chiselTypeClone(_2), chiselTypeClone(_3), chiselTypeClone(_4) + ) + } + + /** [[Data]] equivalent of Scala's [[Tuple5]] + * + * Users may not instantiate this class directly. Instead they should use the implicit conversion from `Tuple5` in + * `chisel3.experimental.conversions` + */ + final class HWTuple5[+A <: Data, +B <: Data, +C <: Data, +D <: Data, +E <: Data] private[chisel3] ( + val _1: A, val _2: B, val _3: C, val _4: D, val _5: E + ) extends Bundle()(Strict) { + // Because this implementation exists in chisel3.core, it cannot compile with the plugin, so we implement the behavior manually + override protected def _usingPlugin: Boolean = true + override protected def _cloneTypeImpl: Bundle = new HWTuple5( + chiselTypeClone(_1), chiselTypeClone(_2), chiselTypeClone(_3), chiselTypeClone(_4), chiselTypeClone(_5) + ) + } + + /** [[Data]] equivalent of Scala's [[Tuple6]] + * + * Users may not instantiate this class directly. Instead they should use the implicit conversion from `Tuple6` in + * `chisel3.experimental.conversions` + */ + final class HWTuple6[+A <: Data, +B <: Data, +C <: Data, +D <: Data, +E <: Data, +F <: Data] private[chisel3] ( + val _1: A, val _2: B, val _3: C, val _4: D, val _5: E, val _6: F + ) extends Bundle()(Strict) { + // Because this implementation exists in chisel3.core, it cannot compile with the plugin, so we implement the behavior manually + override protected def _usingPlugin: Boolean = true + override protected def _cloneTypeImpl: Bundle = new HWTuple6( + chiselTypeClone(_1), chiselTypeClone(_2), chiselTypeClone(_3), chiselTypeClone(_4), chiselTypeClone(_5), + chiselTypeClone(_6) + ) + } + + /** [[Data]] equivalent of Scala's [[Tuple7]] + * + * Users may not instantiate this class directly. Instead they should use the implicit conversion from `Tuple7` in + * `chisel3.experimental.conversions` + */ + final class HWTuple7[+A <: Data, +B <: Data, +C <: Data, +D <: Data, +E <: Data, +F <: Data, +G <: Data] private[chisel3] ( + val _1: A, val _2: B, val _3: C, val _4: D, val _5: E, val _6: F, val _7: G + ) extends Bundle()(Strict) { + // Because this implementation exists in chisel3.core, it cannot compile with the plugin, so we implement the behavior manually + override protected def _usingPlugin: Boolean = true + override protected def _cloneTypeImpl: Bundle = new HWTuple7( + chiselTypeClone(_1), chiselTypeClone(_2), chiselTypeClone(_3), chiselTypeClone(_4), chiselTypeClone(_5), + chiselTypeClone(_6), chiselTypeClone(_7) + ) + } + + /** [[Data]] equivalent of Scala's [[Tuple8]] + * + * Users may not instantiate this class directly. Instead they should use the implicit conversion from `Tuple8` in + * `chisel3.experimental.conversions` + */ + final class HWTuple8[ + +A <: Data, +B <: Data, +C <: Data, +D <: Data, +E <: Data, +F <: Data, +G <: Data, +H <: Data + ] private[chisel3] ( + val _1: A, val _2: B, val _3: C, val _4: D, val _5: E, val _6: F, val _7: G, val _8: H + ) extends Bundle()(Strict) { + // Because this implementation exists in chisel3.core, it cannot compile with the plugin, so we implement the behavior manually + override protected def _usingPlugin: Boolean = true + override protected def _cloneTypeImpl: Bundle = new HWTuple8( + chiselTypeClone(_1), chiselTypeClone(_2), chiselTypeClone(_3), chiselTypeClone(_4), chiselTypeClone(_5), + chiselTypeClone(_6), chiselTypeClone(_7), chiselTypeClone(_8) + ) + } + + /** [[Data]] equivalent of Scala's [[Tuple9]] + * + * Users may not instantiate this class directly. Instead they should use the implicit conversion from `Tuple9` in + * `chisel3.experimental.conversions` + */ + final class HWTuple9[ + +A <: Data, +B <: Data, +C <: Data, +D <: Data, +E <: Data, +F <: Data, +G <: Data, +H <: Data, +I <: Data + ] private[chisel3] ( + val _1: A, val _2: B, val _3: C, val _4: D, val _5: E, val _6: F, val _7: G, val _8: H, val _9: I + ) extends Bundle()(Strict) { + // Because this implementation exists in chisel3.core, it cannot compile with the plugin, so we implement the behavior manually + override protected def _usingPlugin: Boolean = true + override protected def _cloneTypeImpl: Bundle = new HWTuple9( + chiselTypeClone(_1), chiselTypeClone(_2), chiselTypeClone(_3), chiselTypeClone(_4), chiselTypeClone(_5), + chiselTypeClone(_6), chiselTypeClone(_7), chiselTypeClone(_8), chiselTypeClone(_9) + ) + } + + + /** [[Data]] equivalent of Scala's [[Tuple9]] + * + * Users may not instantiate this class directly. Instead they should use the implicit conversion from `Tuple9` in + * `chisel3.experimental.conversions` + */ + final class HWTuple10[ + +A <: Data, +B <: Data, +C <: Data, +D <: Data, +E <: Data, +F <: Data, +G <: Data, +H <: Data, +I <: Data, +J <: Data + ] private[chisel3] ( + val _1: A, val _2: B, val _3: C, val _4: D, val _5: E, val _6: F, val _7: G, val _8: H, val _9: I, val _10: J + ) extends Bundle()(Strict) { + // Because this implementation exists in chisel3.core, it cannot compile with the plugin, so we implement the behavior manually + override protected def _usingPlugin: Boolean = true + override protected def _cloneTypeImpl: Bundle = new HWTuple10( + chiselTypeClone(_1), chiselTypeClone(_2), chiselTypeClone(_3), chiselTypeClone(_4), chiselTypeClone(_5), + chiselTypeClone(_6), chiselTypeClone(_7), chiselTypeClone(_8), chiselTypeClone(_9), chiselTypeClone(_10) + ) } } diff --git a/core/src/main/scala/chisel3/experimental/verification/package.scala b/core/src/main/scala/chisel3/experimental/verification/package.scala deleted file mode 100644 index 190083fd..00000000 --- a/core/src/main/scala/chisel3/experimental/verification/package.scala +++ /dev/null @@ -1,60 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 - -package chisel3.experimental - -import chisel3._ -import chisel3.internal.Builder -import chisel3.internal.firrtl.{Formal, Verification} -import chisel3.internal.sourceinfo.SourceInfo - -package object verification { - - object assert { - /** Named class for assertions. */ - final class Assert(private[chisel3] val predicate: Bool) extends BaseSim - - - def apply(predicate: Bool, msg: String = "")( - implicit sourceInfo: SourceInfo, - compileOptions: CompileOptions): Assert = { - val a = new Assert(predicate) - when (!Module.reset.asBool) { - val clock = Module.clock - Builder.pushCommand(Verification(a, Formal.Assert, sourceInfo, clock.ref, predicate.ref, msg)) - } - a - } - } - - object assume { - /** Named class for assumes. */ - final class Assume(private[chisel3] val predicate: Bool) extends BaseSim - - def apply(predicate: Bool, msg: String = "")( - implicit sourceInfo: SourceInfo, - compileOptions: CompileOptions): Assume = { - val a = new Assume(predicate) - when (!Module.reset.asBool) { - val clock = Module.clock - Builder.pushCommand(Verification(a, Formal.Assume, sourceInfo, clock.ref, predicate.ref, msg)) - } - a - } - } - - object cover { - /** Named class for covers. */ - final class Cover(private[chisel3] val predicate: Bool) extends BaseSim - - def apply(predicate: Bool, msg: String = "")( - implicit sourceInfo: SourceInfo, - compileOptions: CompileOptions): Cover = { - val clock = Module.clock - val c = new Cover(predicate) - when (!Module.reset.asBool) { - Builder.pushCommand(Verification(c, Formal.Cover, sourceInfo, clock.ref, predicate.ref, msg)) - } - c - } - } -} |
