Skip to content

Commit

Permalink
Add DataProduct for Iterables and primitive types (#3856)
Browse files Browse the repository at this point in the history
  • Loading branch information
jackkoenig authored Feb 23, 2024
1 parent eadde6f commit a0ac3fd
Show file tree
Hide file tree
Showing 3 changed files with 73 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ trait DataProduct[-A] {

/** Low priority built-in implementations of [[DataProduct]]
*
* @note This trait exists so that `dataDataProduct` can be lower priority than `seqDataProduct` to resolve ambiguity
* @note This trait exists so that `dataDataProduct` can be lower priority than `iterableDataProduct` to resolve ambiguity
*/
sealed trait LowPriorityDataProduct {

Expand All @@ -63,6 +63,25 @@ sealed trait LowPriorityDataProduct {
*/
object DataProduct extends LowPriorityDataProduct {

/** Factory method for constructing [[DataProduct]]s */
def apply[A](f: (A, String) => Iterator[(Data, String)]): DataProduct[A] = new DataProduct[A] {
def dataIterator(a: A, path: String): Iterator[(Data, String)] = f(a, path)
}

/** Factory for constructing [[DataProduct]] for types that do not contain any [[Data]] */
def empty[A]: DataProduct[A] = apply[A] { case _ => Iterator.empty }

// DataProducts for simple primitive types
implicit val charDataProduct: DataProduct[Char] = empty
implicit val stringDataProduct: DataProduct[String] = empty
implicit val intDataProduct: DataProduct[Int] = empty
implicit val byteDataProduct: DataProduct[Byte] = empty
implicit val shortDataProduct: DataProduct[Short] = empty
implicit val longDataProduct: DataProduct[Long] = empty
implicit val bigIntDataProduct: DataProduct[BigInt] = empty
implicit val floatDataProduct: DataProduct[Float] = empty
implicit val doubleDataProduct: DataProduct[Double] = empty

/** [[DataProduct]] implementation for [[BaseModule]] */
implicit val userModuleDataProduct: DataProduct[BaseModule] = new DataProduct[BaseModule] {
def dataIterator(a: BaseModule, path: String): Iterator[(Data, String)] = {
Expand All @@ -82,7 +101,8 @@ object DataProduct extends LowPriorityDataProduct {
}

/** [[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]] {
@deprecated("Use iterableDataProduct instead", "Chisel 7.0")
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 {
Expand All @@ -92,6 +112,17 @@ object DataProduct extends LowPriorityDataProduct {
}
}

/** [[DataProduct]] implementation for any `Iterable[A]` where `A` has an implementation of `DataProduct`. */
implicit def iterableDataProduct[A: DataProduct, F[A] <: IterableOnce[A]]: DataProduct[F[A]] = new DataProduct[F[A]] {
def dataIterator(a: F[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 [[scala.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)] = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -514,6 +514,7 @@ object Lookupable {
implicit val lookupShort: SimpleLookupable[Short] = new SimpleLookupable[Short]()
implicit val lookupLong: SimpleLookupable[Long] = new SimpleLookupable[Long]()
implicit val lookupFloat: SimpleLookupable[Float] = new SimpleLookupable[Float]()
implicit val lookupDouble: SimpleLookupable[Double] = new SimpleLookupable[Double]()
implicit val lookupChar: SimpleLookupable[Char] = new SimpleLookupable[Char]()
implicit val lookupString: SimpleLookupable[String] = new SimpleLookupable[String]()
implicit val lookupBoolean: SimpleLookupable[Boolean] = new SimpleLookupable[Boolean]()
Expand Down
39 changes: 39 additions & 0 deletions src/test/scala/chiselTests/experimental/DataView.scala
Original file line number Diff line number Diff line change
Expand Up @@ -552,6 +552,45 @@ class DataViewSpec extends ChiselFlatSpec {
verilog should include("assign z = sel ? b : d;")
}

it should "support primitive types in the view target" in {
class MyBundle(val name: String) extends Bundle {
val x = UInt(8.W)
}
implicit val view: DataView[(UInt, Char, String, Int, Byte, Short, Long, BigInt, Float, Double), MyBundle] =
DataView(
tup => new MyBundle(tup.productIterator.toList.tail.mkString("_")),
_._1 -> _.x
)
class MyModule extends Module {
val in = IO(Input(UInt(8.W)))
val bun = (in, 'a', "b", 0, 1.toByte, 2.toShort, 3L, BigInt(4), 5.0f, 6.0).viewAs[MyBundle]
val out = IO(Output(chiselTypeOf(bun)))
out := bun
bun.name should be("a_b_0_1_2_3_4_5.0_6.0")
}
val chirrtl = ChiselStage.emitCHIRRTL(new MyModule)
chirrtl should include("connect out.x, in")
}

it should "support views of Options" in {
class MyBundle(w: Option[Int]) extends Bundle {
val x = w.map(v => UInt(v.W))
}
implicit val view: DataView[Option[UInt], MyBundle] = DataView.mapping(
opt => new MyBundle(opt.map(_.getWidth)),
{ case (opt, bun) => opt.zip(bun.x).map { case (o, b) => o -> b } }
)
class MyModule extends Module {
val in = IO(Input(UInt(8.W)))
val out1 = IO(Output(new MyBundle(Some(8))))
val out2 = IO(Output(new MyBundle(None)))
out1 := Option(in).viewAs[MyBundle]
out2 := Option.empty[UInt].viewAs[MyBundle]
}
val chirrtl = ChiselStage.emitCHIRRTL(new MyModule)
chirrtl should include("connect out1.x, in")
}

// This example should be turned into a built-in feature
it should "enable viewing Seqs as Vecs" in {

Expand Down

0 comments on commit a0ac3fd

Please sign in to comment.