diff options
| author | Jack Koenig | 2021-12-08 14:21:44 -0800 |
|---|---|---|
| committer | GitHub | 2021-12-08 14:21:44 -0800 |
| commit | 08271081e4af2025fc6c6af97511fd110ef65e5c (patch) | |
| tree | 891f9505ebf9515d3f5fc7205cdbdd7bfc0466bb /src/test/scala/chiselTests/experimental | |
| parent | e85bfebb5d661de41f9ccac300fb48bf92840cfe (diff) | |
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
Diffstat (limited to 'src/test/scala/chiselTests/experimental')
4 files changed, 171 insertions, 99 deletions
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))) |
