From 08271081e4af2025fc6c6af97511fd110ef65e5c Mon Sep 17 00:00:00 2001 From: Jack Koenig Date: Wed, 8 Dec 2021 14:21:44 -0800 Subject: Implement DataViews for Seq and Tuple (#2277) * DataProducts for Seq and Tuple2-10 in DataProduct companion object * DataViews for Seq and Tuple 2-10 in DataView companion object * HWTuple2-10 Bundles in chisel3.experimental * Implicit conversions from Seq to Vec and Tuple to HWTuple in chisel3.experimental.conversions--- .../experimental/dataview/DataProduct.scala | 248 ++++++++++++++++++++- .../chisel3/experimental/dataview/DataView.scala | 239 +++++++++++++++++++- .../main/scala/chisel3/experimental/package.scala | 149 ++++++++++++- docs/src/explanations/dataview.md | 40 ++-- .../chisel3/experimental/conversions/package.scala | 128 +++++++++++ .../scala/chiselTests/experimental/DataView.scala | 102 +-------- .../experimental/DataViewTargetSpec.scala | 3 +- .../scala/chiselTests/experimental/Tuple.scala | 163 ++++++++++++++ .../experimental/hierarchy/InstanceSpec.scala | 2 +- 9 files changed, 946 insertions(+), 128 deletions(-) create mode 100644 src/main/scala/chisel3/experimental/conversions/package.scala create mode 100644 src/test/scala/chiselTests/experimental/Tuple.scala 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/package.scala b/core/src/main/scala/chisel3/experimental/package.scala index 0fc79487..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. @@ -166,4 +167,150 @@ package object experimental { val prefix = chisel3.internal.prefix // Use to remove prefixes not in provided scope val noPrefix = chisel3.internal.noPrefix + + // ****************************** 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/docs/src/explanations/dataview.md b/docs/src/explanations/dataview.md index a04bbec7..bb8dbdd1 100644 --- a/docs/src/explanations/dataview.md +++ b/docs/src/explanations/dataview.md @@ -10,7 +10,6 @@ _New in Chisel 3.5_ ```scala mdoc:invisible import chisel3._ -import chisel3.stage.ChiselStage.emitVerilog ``` ## Introduction @@ -91,7 +90,7 @@ class MyModule extends RawModule { Of course, this would result in very different looking Verilog: ```scala mdoc:verilog -emitVerilog(new MyModule { +getVerilogString(new MyModule { override def desiredName = "MyModule" axi := DontCare // Just to generate Verilog in this stub }) @@ -147,7 +146,7 @@ class AXIStub extends RawModule { This will generate Verilog that matches the standard naming convention: ```scala mdoc:verilog -emitVerilog(new AXIStub) +getVerilogString(new AXIStub) ``` Note that if both the _Target_ and the _View_ types are subtypes of `Data` (as they are in this example), @@ -175,7 +174,7 @@ class ConnectionExample extends RawModule { This results in the corresponding fields being connected in the emitted Verilog: ```scala mdoc:verilog -emitVerilog(new ConnectionExample) +getVerilogString(new ConnectionExample) ``` ## Other Use Cases @@ -206,17 +205,6 @@ The issue, is that Chisel primitives like `Mux` and `:=` only operate on subtype Tuples (as members of the Scala standard library), are not subclasses of `Data`. `DataView` provides a mechanism to _view_ a `Tuple` as if it were a `Data`: - - -```scala mdoc:invisible -// ProductDataProduct -implicit val productDataProduct: DataProduct[Product] = new DataProduct[Product] { - def dataIterator(a: Product, path: String): Iterator[(Data, String)] = { - a.productIterator.zipWithIndex.collect { case (d: Data, i) => d -> s"$path._$i" } - } -} -``` - ```scala mdoc // We need a type to represent the Tuple class HWTuple2[A <: Data, B <: Data](val _1: A, val _2: B) extends Bundle @@ -259,16 +247,24 @@ class TupleExample extends RawModule { ```scala mdoc:invisible // Always emit Verilog to make sure it actually works -emitVerilog(new TupleExample) +getVerilogString(new TupleExample) ``` Note that this example ignored `DataProduct` which is another required piece (see [the documentation about it below](#dataproduct)). -All of this is slated to be included the Chisel standard library. +All of this is available to users via a single import: +```scala mdoc:reset +import chisel3.experimental.conversions._ +``` ## Totality and PartialDataView +```scala mdoc:reset:invisible +import chisel3._ +import chisel3.experimental.dataview._ +``` + A `DataView` is _total_ if all fields of the _Target_ type and all fields of the _View_ type are included in the mapping. Chisel will error if a field is accidentally left out from a `DataView`. @@ -293,7 +289,7 @@ class BadMapping extends Module { out := in.viewAs[BundleB] } // We must run Chisel to see the error -emitVerilog(new BadMapping) +getVerilogString(new BadMapping) ``` As that error suggests, if we *want* the view to be non-total, we can use a `PartialDataView`: @@ -309,7 +305,7 @@ class PartialDataViewModule extends Module { ``` ```scala mdoc:verilog -emitVerilog(new PartialDataViewModule) +getVerilogString(new PartialDataViewModule) ``` While `PartialDataViews` need not be total for the _Target_, both `PartialDataViews` and `DataViews` @@ -327,7 +323,7 @@ class PartialDataViewModule2 extends Module { out.viewAs[BundleA] := in } // We must run Chisel to see the error -emitVerilog(new PartialDataViewModule2) +getVerilogString(new PartialDataViewModule2) ``` As noted, the mapping must **always** be total for the `View`. @@ -440,7 +436,7 @@ class FooToBar extends Module { ``` ```scala mdoc:verilog -emitVerilog(new FooToBar) +getVerilogString(new FooToBar) ``` However, it's possible that some user of `Foo` and `Bar` wants different behavior, @@ -460,7 +456,7 @@ class FooToBarSwizzled extends Module { ``` ```scala mdoc:verilog -emitVerilog(new FooToBarSwizzled) +getVerilogString(new FooToBarSwizzled) ``` ### DataProduct diff --git a/src/main/scala/chisel3/experimental/conversions/package.scala b/src/main/scala/chisel3/experimental/conversions/package.scala new file mode 100644 index 00000000..574f9f96 --- /dev/null +++ b/src/main/scala/chisel3/experimental/conversions/package.scala @@ -0,0 +1,128 @@ + +package chisel3.experimental + +import chisel3._ +import chisel3.experimental.dataview._ +import scala.language.implicitConversions + +/** Implicit conversions from some Scala standard library types and [[Data]] + * + * @note As this leans heavily on the experimental [[DataView]] feature, these APIs are experimental and subject to change + */ +package object conversions { + + /** Implicit conversion between `Seq` and `Vec` */ + implicit def seq2vec[A : DataProduct, B <: Data](xs: Seq[A])(implicit dv: DataView[A, B]): Vec[B] = + xs.viewAs[Vec[B]] + + /** Implicit conversion between [[Tuple2]] and [[HWTuple2]] */ + implicit def tuple2hwtuple[T1 : DataProduct, T2 : DataProduct, V1 <: Data, V2 <: Data]( + tup: (T1, T2) + )( + implicit v1: DataView[T1, V1], v2: DataView[T2, V2] + ): HWTuple2[V1, V2] = { + tup.viewAs[HWTuple2[V1, V2]] + } + + /** Implicit conversion between [[Tuple3]] and [[HWTuple3]] */ + implicit def tuple3hwtuple[T1 : DataProduct, T2 : DataProduct, T3 : DataProduct, V1 <: Data, V2 <: Data, V3 <: Data]( + tup: (T1, T2, T3) + )( + implicit v1: DataView[T1, V1], v2: DataView[T2, V2], v3: DataView[T3, V3] + ): HWTuple3[V1, V2, V3] = { + tup.viewAs[HWTuple3[V1, V2, V3]] + } + + /** Implicit conversion between [[Tuple4]] and [[HWTuple4]] */ + implicit def tuple4hwtuple[ + T1 : DataProduct, T2 : DataProduct, T3 : DataProduct, T4 : DataProduct, + V1 <: Data, V2 <: Data, V3 <: Data, V4 <: Data + ]( + tup: (T1, T2, T3, T4) + )( + implicit v1: DataView[T1, V1], v2: DataView[T2, V2], v3: DataView[T3, V3], v4: DataView[T4, V4] + ): HWTuple4[V1, V2, V3, V4] = { + tup.viewAs[HWTuple4[V1, V2, V3, V4]] + } + + /** Implicit conversion between [[Tuple5]] and [[HWTuple5]] */ + implicit def tuple5hwtuple[ + T1 : DataProduct, T2 : DataProduct, T3 : DataProduct, T4 : DataProduct, T5 : DataProduct, + V1 <: Data, V2 <: Data, V3 <: Data, V4 <: Data, V5 <: Data + ]( + tup: (T1, T2, T3, T4, T5) + )( + implicit v1: DataView[T1, V1], v2: DataView[T2, V2], v3: DataView[T3, V3], v4: DataView[T4, V4], v5: DataView[T5, V5] + ): HWTuple5[V1, V2, V3, V4, V5] = { + tup.viewAs[HWTuple5[V1, V2, V3, V4, V5]] + } + + /** Implicit conversion between [[Tuple6]] and [[HWTuple6]] */ + implicit def tuple6hwtuple[ + T1 : DataProduct, T2 : DataProduct, T3 : DataProduct, T4 : DataProduct, T5 : DataProduct, T6 : DataProduct, + V1 <: Data, V2 <: Data, V3 <: Data, V4 <: Data, V5 <: Data, V6 <: Data + ]( + tup: (T1, T2, T3, T4, T5, T6) + )( + 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] + ): HWTuple6[V1, V2, V3, V4, V5, V6] = { + tup.viewAs[HWTuple6[V1, V2, V3, V4, V5, V6]] + } + + /** Implicit conversion between [[Tuple7]] and [[HWTuple7]] */ + implicit def tuple7hwtuple[ + 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 + ]( + tup: (T1, T2, T3, T4, T5, T6, T7) + )( + 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] + ): HWTuple7[V1, V2, V3, V4, V5, V6, V7] = { + tup.viewAs[HWTuple7[V1, V2, V3, V4, V5, V6, V7]] + } + + /** Implicit conversion between [[Tuple8]] and [[HWTuple8]] */ + implicit def tuple8hwtuple[ + 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 + ]( + tup: (T1, T2, T3, T4, T5, T6, T7, T8) + )( + 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] + ): HWTuple8[V1, V2, V3, V4, V5, V6, V7, V8] = { + tup.viewAs[HWTuple8[V1, V2, V3, V4, V5, V6, V7, V8]] + } + + /** Implicit conversion between [[Tuple9]] and [[HWTuple9]] */ + implicit def tuple9hwtuple[ + 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 + ]( + tup: (T1, T2, T3, T4, T5, T6, T7, T8, T9) + )( + 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] + ): HWTuple9[V1, V2, V3, V4, V5, V6, V7, V8, V9] = { + tup.viewAs[HWTuple9[V1, V2, V3, V4, V5, V6, V7, V8, V9]] + } + + /** Implicit conversion between [[Tuple10]] and [[HWTuple10]] */ + implicit def tuple10hwtuple[ + 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 + ]( + tup: (T1, T2, T3, T4, T5, T6, T7, T8, T9, T10) + )( + 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] + ): HWTuple10[V1, V2, V3, V4, V5, V6, V7, V8, V9, V10] = { + tup.viewAs[HWTuple10[V1, V2, V3, V4, V5, V6, V7, V8, V9, V10]] + } +} diff --git a/src/test/scala/chiselTests/experimental/DataView.scala b/src/test/scala/chiselTests/experimental/DataView.scala index d1620e88..399b0cbc 100644 --- a/src/test/scala/chiselTests/experimental/DataView.scala +++ b/src/test/scala/chiselTests/experimental/DataView.scala @@ -5,7 +5,9 @@ package chiselTests.experimental import chiselTests.ChiselFlatSpec import chisel3._ import chisel3.experimental.dataview._ +import chisel3.experimental.conversions._ import chisel3.experimental.DataMirror.internal.chiselTypeClone +import chisel3.experimental.HWTuple2 import chisel3.stage.ChiselStage import chisel3.util.{Decoupled, DecoupledIO} @@ -50,69 +52,6 @@ object FlatDecoupledDataView { implicit val view2 = view.invert(_ => new FlatDecoupled) } -// This should become part of Chisel in a later PR -object Tuple2DataProduct { - implicit def tuple2DataProduct[A : DataProduct, B : DataProduct] = 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") - } - } -} - -// This should become part of Chisel in a later PR -object HWTuple { - import Tuple2DataProduct._ - - class HWTuple2[A <: Data, B <: Data](val _1: A, val _2: B) extends Bundle - - implicit def view[T1 : DataProduct, T2 : DataProduct, V1 <: Data, V2 <: Data]( - implicit v1: DataView[T1, V1], v2: DataView[T2, V2] - ): 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) - } - ) - - implicit def tuple2hwtuple[T1 : DataProduct, T2 : DataProduct, V1 <: Data, V2 <: Data]( - tup: (T1, T2))(implicit v1: DataView[T1, V1], v2: DataView[T2, V2] - ): HWTuple2[V1, V2] = tup.viewAs[HWTuple2[V1, V2]] -} - -// This should become part of Chisel in a later PR -object SeqDataProduct { - // Should we special case Seq[Data]? - 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]") - } - } - } -} - -object SeqToVec { - import SeqDataProduct._ - - // TODO this would need a better way to determine the prototype for the Vec - implicit def seqVec[A : DataProduct, B <: Data](implicit dv: DataView[A, B]): DataView[Seq[A], Vec[B]] = - DataView.mapping[Seq[A], Vec[B]]( - xs => Vec(xs.size, chiselTypeClone(xs.head.viewAs[B])), // xs.head is not correct in general - { case (s, v) => s.zip(v).map { case (a, b) => a.viewAs[B] -> b } } - ) - - implicit def seq2Vec[A : DataProduct, B <: Data](xs: Seq[A])(implicit dv: DataView[A, B]): Vec[B] = - xs.viewAs[Vec[B]] -} - class DataViewSpec extends ChiselFlatSpec { behavior of "DataView" @@ -327,15 +266,14 @@ class DataViewSpec extends ChiselFlatSpec { chirrtl should include ("z.fizz <= b.foo") } - // This example should be turned into a built-in feature - it should "enable implementing \"HardwareTuple\"" in { - import HWTuple._ - + it should "enable using Seq like Data" in { class MyModule extends Module { val a, b, c, d = IO(Input(UInt(8.W))) val sel = IO(Input(Bool())) val y, z = IO(Output(UInt(8.W))) - (y, z) := Mux(sel, (a, b), (c, d)) + // Unclear why the implicit conversion does not work in this case for Seq + // That being said, it's easy enough to cast via `.viewAs` with or without + Seq(y, z) := Mux(sel, Seq(a, b).viewAs, Seq(c, d).viewAs[Vec[UInt]]) } // Verilog instead of CHIRRTL because the optimizations make it much prettier val verilog = ChiselStage.emitVerilog(new MyModule) @@ -343,25 +281,8 @@ class DataViewSpec extends ChiselFlatSpec { verilog should include ("assign z = sel ? b : d;") } - it should "support nesting of tuples" in { - import Tuple2DataProduct._ - import HWTuple._ - - class MyModule extends Module { - val a, b, c, d = IO(Input(UInt(8.W))) - val w, x, y, z = IO(Output(UInt(8.W))) - ((w, x), (y, z)) := ((a, b), (c, d)) - } - val chirrtl = ChiselStage.emitChirrtl(new MyModule) - chirrtl should include ("w <= a") - chirrtl should include ("x <= b") - chirrtl should include ("y <= c") - chirrtl should include ("z <= d") - } - // This example should be turned into a built-in feature it should "enable viewing Seqs as Vecs" in { - import SeqToVec._ class MyModule extends Module { val a, b, c = IO(Input(UInt(8.W))) @@ -376,11 +297,6 @@ class DataViewSpec extends ChiselFlatSpec { } it should "support recursive composition of views" in { - import Tuple2DataProduct._ - import SeqDataProduct._ - import SeqToVec._ - import HWTuple._ - class MyModule extends Module { val a, b, c, d = IO(Input(UInt(8.W))) val w, x, y, z = IO(Output(UInt(8.W))) @@ -398,10 +314,6 @@ class DataViewSpec extends ChiselFlatSpec { } it should "error if you try to dynamically index a Vec view" in { - import SeqDataProduct._ - import SeqToVec._ - import Tuple2DataProduct._ - import HWTuple._ class MyModule extends Module { val inA, inB = IO(Input(UInt(8.W))) @@ -434,7 +346,6 @@ class DataViewSpec extends ChiselFlatSpec { } it should "error if the mapping is non-total in the target" in { - import Tuple2DataProduct._ implicit val dv = DataView[(UInt, UInt), UInt](_ => UInt(), _._1 -> _) class MyModule extends Module { val a, b = IO(Input(UInt(8.W))) @@ -533,7 +444,6 @@ class DataViewSpec extends ChiselFlatSpec { } it should "NOT error if the mapping is non-total in the target" in { - import Tuple2DataProduct._ implicit val dv = PartialDataView[(UInt, UInt), UInt](_ => UInt(), _._2 -> _) class MyModule extends Module { val a, b = IO(Input(UInt(8.W))) diff --git a/src/test/scala/chiselTests/experimental/DataViewTargetSpec.scala b/src/test/scala/chiselTests/experimental/DataViewTargetSpec.scala index 92091631..a17b0f40 100644 --- a/src/test/scala/chiselTests/experimental/DataViewTargetSpec.scala +++ b/src/test/scala/chiselTests/experimental/DataViewTargetSpec.scala @@ -4,8 +4,8 @@ package chiselTests.experimental import chisel3._ import chisel3.experimental.dataview._ +import chisel3.experimental.conversions._ import chisel3.experimental.{ChiselAnnotation, annotate} -import chisel3.stage.ChiselStage import chiselTests.ChiselFlatSpec object DataViewTargetSpec { @@ -127,7 +127,6 @@ class DataViewTargetSpec extends ChiselFlatSpec { } it should "support annotating views that cannot be mapped to a single ReferenceTarget" in { - import HWTuple._ class MyBundle extends Bundle { val a, b = Input(UInt(8.W)) val c, d = Output(UInt(8.W)) diff --git a/src/test/scala/chiselTests/experimental/Tuple.scala b/src/test/scala/chiselTests/experimental/Tuple.scala new file mode 100644 index 00000000..5f897fbc --- /dev/null +++ b/src/test/scala/chiselTests/experimental/Tuple.scala @@ -0,0 +1,163 @@ +// See LICENSE for license details. + +package chiselTests.experimental + +import chiselTests.ChiselFlatSpec +import chisel3._ +import chisel3.experimental.conversions._ +import chisel3.stage.ChiselStage + +class TupleSpec extends ChiselFlatSpec { + + behavior of "Tuple" + + it should "enable using Tuple2 like Data" in { + class MyModule extends Module { + val a, b, c, d = IO(Input(UInt(8.W))) + val sel = IO(Input(Bool())) + val y, z = IO(Output(UInt(8.W))) + (y, z) := Mux(sel, (a, b), (c, d)) + } + // Verilog instead of CHIRRTL because the optimizations make it much prettier + val verilog = ChiselStage.emitVerilog(new MyModule) + verilog should include ("assign y = sel ? a : c;") + verilog should include ("assign z = sel ? b : d;") + } + + it should "support nesting of tuples" in { + class MyModule extends Module { + val a, b, c, d = IO(Input(UInt(8.W))) + val w, x, y, z = IO(Output(UInt(8.W))) + ((w, x), (y, z)) := ((a, b), (c, d)) + } + val chirrtl = ChiselStage.emitChirrtl(new MyModule) + chirrtl should include ("w <= a") + chirrtl should include ("x <= b") + chirrtl should include ("y <= c") + chirrtl should include ("z <= d") + } + + it should "enable using Tuple3 like Data" in { + class MyModule extends Module { + val a, b, c = IO(Input(UInt(8.W))) + val f, g, h = IO(Input(UInt(8.W))) + val sel = IO(Input(Bool())) + val v, w, x = IO(Output(UInt(8.W))) + (v, w, x) := Mux(sel, (a, b, c), (f, g, h)) + } + // Verilog instead of CHIRRTL because the optimizations make it much prettier + val verilog = ChiselStage.emitVerilog(new MyModule) + verilog should include ("assign v = sel ? a : f;") + verilog should include ("assign w = sel ? b : g;") + verilog should include ("assign x = sel ? c : h;") + } + + it should "enable using Tuple4 like Data" in { + class MyModule extends Module { + val a, b, c, d = IO(Input(UInt(8.W))) + val f, g, h, i = IO(Input(UInt(8.W))) + val sel = IO(Input(Bool())) + val v, w, x, y = IO(Output(UInt(8.W))) + (v, w, x, y) := Mux(sel, (a, b, c, d), (f, g, h, i)) + } + // Verilog instead of CHIRRTL because the optimizations make it much prettier + val verilog = ChiselStage.emitVerilog(new MyModule) + verilog should include ("assign v = sel ? a : f;") + verilog should include ("assign w = sel ? b : g;") + verilog should include ("assign x = sel ? c : h;") + verilog should include ("assign y = sel ? d : i;") + } + + it should "enable using Tuple5 like Data" in { + class MyModule extends Module { + val a0, a1, a2, a3, a4 = IO(Input(UInt(8.W))) + val b0, b1, b2, b3, b4 = IO(Input(UInt(8.W))) + val sel = IO(Input(Bool())) + val z0, z1, z2, z3, z4 = IO(Output(UInt(8.W))) + (z0, z1, z2, z3, z4) := Mux(sel, (a0, a1, a2, a3, a4), (b0, b1, b2, b3, b4)) + } + // Verilog instead of CHIRRTL because the optimizations make it much prettier + val verilog = ChiselStage.emitVerilog(new MyModule) + for (i <- 0 until 5) { + verilog should include(s"assign z$i = sel ? a$i : b$i;") + } + } + + it should "enable using Tuple6 like Data" in { + class MyModule extends Module { + val a0, a1, a2, a3, a4, a5 = IO(Input(UInt(8.W))) + val b0, b1, b2, b3, b4, b5 = IO(Input(UInt(8.W))) + val sel = IO(Input(Bool())) + val z0, z1, z2, z3, z4, z5 = IO(Output(UInt(8.W))) + (z0, z1, z2, z3, z4, z5) := Mux(sel, (a0, a1, a2, a3, a4, a5), (b0, b1, b2, b3, b4, b5)) + } + // Verilog instead of CHIRRTL because the optimizations make it much prettier + val verilog = ChiselStage.emitVerilog(new MyModule) + for (i <- 0 until 6) { + verilog should include(s"assign z$i = sel ? a$i : b$i;") + } + } + + it should "enable using Tuple7 like Data" in { + class MyModule extends Module { + val a0, a1, a2, a3, a4, a5, a6 = IO(Input(UInt(8.W))) + val b0, b1, b2, b3, b4, b5, b6 = IO(Input(UInt(8.W))) + val sel = IO(Input(Bool())) + val z0, z1, z2, z3, z4, z5, z6 = IO(Output(UInt(8.W))) + (z0, z1, z2, z3, z4, z5, z6) := Mux(sel, (a0, a1, a2, a3, a4, a5, a6), (b0, b1, b2, b3, b4, b5, b6)) + } + // Verilog instead of CHIRRTL because the optimizations make it much prettier + val verilog = ChiselStage.emitVerilog(new MyModule) + for (i <- 0 until 7) { + verilog should include(s"assign z$i = sel ? a$i : b$i;") + } + } + + it should "enable using Tuple8 like Data" in { + class MyModule extends Module { + val a0, a1, a2, a3, a4, a5, a6, a7 = IO(Input(UInt(8.W))) + val b0, b1, b2, b3, b4, b5, b6, b7 = IO(Input(UInt(8.W))) + val sel = IO(Input(Bool())) + val z0, z1, z2, z3, z4, z5, z6, z7 = IO(Output(UInt(8.W))) + (z0, z1, z2, z3, z4, z5, z6, z7) := Mux(sel, (a0, a1, a2, a3, a4, a5, a6, a7), (b0, b1, b2, b3, b4, b5, b6, b7)) + } + // Verilog instead of CHIRRTL because the optimizations make it much prettier + val verilog = ChiselStage.emitVerilog(new MyModule) + for (i <- 0 until 8) { + verilog should include(s"assign z$i = sel ? a$i : b$i;") + } + } + + it should "enable using Tuple9 like Data" in { + class MyModule extends Module { + val a0, a1, a2, a3, a4, a5, a6, a7, a8 = IO(Input(UInt(8.W))) + val b0, b1, b2, b3, b4, b5, b6, b7, b8 = IO(Input(UInt(8.W))) + val sel = IO(Input(Bool())) + val z0, z1, z2, z3, z4, z5, z6, z7, z8 = IO(Output(UInt(8.W))) + (z0, z1, z2, z3, z4, z5, z6, z7, z8) := + Mux(sel, (a0, a1, a2, a3, a4, a5, a6, a7, a8), (b0, b1, b2, b3, b4, b5, b6, b7, b8)) + } + // Verilog instead of CHIRRTL because the optimizations make it much prettier + val verilog = ChiselStage.emitVerilog(new MyModule) + for (i <- 0 until 9) { + verilog should include(s"assign z$i = sel ? a$i : b$i;") + } + } + + it should "enable using Tuple10 like Data" in { + class MyModule extends Module { + val a0, a1, a2, a3, a4, a5, a6, a7, a8, a9 = IO(Input(UInt(8.W))) + val b0, b1, b2, b3, b4, b5, b6, b7, b8, b9 = IO(Input(UInt(8.W))) + val sel = IO(Input(Bool())) + val z0, z1, z2, z3, z4, z5, z6, z7, z8, z9 = IO(Output(UInt(8.W))) + (z0, z1, z2, z3, z4, z5, z6, z7, z8, z9) := + Mux(sel, (a0, a1, a2, a3, a4, a5, a6, a7, a8, a9), (b0, b1, b2, b3, b4, b5, b6, b7, b8, b9)) + } + // Verilog instead of CHIRRTL because the optimizations make it much prettier + val verilog = ChiselStage.emitVerilog(new MyModule) + for (i <- 0 until 10) { + verilog should include(s"assign z$i = sel ? a$i : b$i;") + } + } + +} diff --git a/src/test/scala/chiselTests/experimental/hierarchy/InstanceSpec.scala b/src/test/scala/chiselTests/experimental/hierarchy/InstanceSpec.scala index 929e3875..9ceb9b40 100644 --- a/src/test/scala/chiselTests/experimental/hierarchy/InstanceSpec.scala +++ b/src/test/scala/chiselTests/experimental/hierarchy/InstanceSpec.scala @@ -629,7 +629,7 @@ class InstanceSpec extends ChiselFunSpec with Utils { } it("7.3: should work with DataView + implicit conversion") { - import chiselTests.experimental.SeqToVec._ + import chisel3.experimental.conversions._ @instantiable class MyModule extends RawModule { private val a = IO(Input(UInt(8.W))) -- cgit v1.2.3