summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormergify[bot]2022-11-04 18:20:07 +0000
committerGitHub2022-11-04 18:20:07 +0000
commit4149157df6531d124483d992daf96cf4e62a0f0c (patch)
tree76b4e80517168c5d0704e24c097a3c176417a811
parent0750bc2f46d49c8fdfd0c07a2ac80c74311b3f15 (diff)
Add PartialDataView.supertype (backport #2826) (#2827)
* Add PartialDataView.supertype (#2826) This factory method makes it easy to create PartialDataViews from a Bundle type to its supertype. Because of the typing relationship, there is no need to provide a mapping between fields. The only thing necessary is to provide a function for constructing an instance of the supertype from an instance of the subtype. (cherry picked from commit 251d454a224e5a961438ba0ea41134d7da7a5992) # Conflicts: # core/src/main/scala/chisel3/experimental/dataview/package.scala # src/test/scala/chiselTests/experimental/DataView.scala * Resolve backport conflicts Co-authored-by: Jack Koenig <koenig@sifive.com>
-rw-r--r--core/src/main/scala/chisel3/experimental/dataview/DataView.scala23
-rw-r--r--core/src/main/scala/chisel3/experimental/dataview/package.scala14
-rw-r--r--docs/src/cookbooks/dataview.md35
-rw-r--r--src/test/scala/chiselTests/experimental/DataView.scala22
4 files changed, 82 insertions, 12 deletions
diff --git a/core/src/main/scala/chisel3/experimental/dataview/DataView.scala b/core/src/main/scala/chisel3/experimental/dataview/DataView.scala
index 7f20964d..cc555b11 100644
--- a/core/src/main/scala/chisel3/experimental/dataview/DataView.scala
+++ b/core/src/main/scala/chisel3/experimental/dataview/DataView.scala
@@ -592,4 +592,27 @@ object PartialDataView {
implicit sourceInfo: SourceInfo
): DataView[T, V] =
new DataView[T, V](mkView, mapping, _total = false)
+
+ /** Constructs a non-total [[DataView]] mapping from a [[Bundle]] type to a parent [[Bundle]] type
+ *
+ * @param mkView a function constructing an instance `V` from an instance of `T`
+ * @return the [[DataView]] that enables viewing instances of a [[Bundle]] as instances of a parent type
+ */
+ def supertype[T <: Bundle, V <: Bundle](
+ mkView: T => V
+ )(
+ implicit ev: SubTypeOf[T, V],
+ sourceInfo: SourceInfo
+ ): DataView[T, V] =
+ mapping[T, V](
+ mkView,
+ {
+ case (a, b) =>
+ val aElts = a.elements
+ val bElts = b.elements
+ val bKeys = bElts.keySet
+ val keys = aElts.keysIterator.filter(bKeys.contains)
+ keys.map(k => aElts(k) -> bElts(k)).toSeq
+ }
+ )
}
diff --git a/core/src/main/scala/chisel3/experimental/dataview/package.scala b/core/src/main/scala/chisel3/experimental/dataview/package.scala
index 71ae2d8f..a52e88cf 100644
--- a/core/src/main/scala/chisel3/experimental/dataview/package.scala
+++ b/core/src/main/scala/chisel3/experimental/dataview/package.scala
@@ -43,24 +43,14 @@ package object dataview {
"${A} is not a subtype of ${B}! Did you mean .viewAs[${B}]? " +
"Please see https://www.chisel-lang.org/chisel3/docs/cookbooks/dataview"
)
- private type SubTypeOf[A, B] = A <:< B
+ private[dataview] type SubTypeOf[A, B] = A <:< B
/** Provides `viewAsSupertype` for subclasses of [[Bundle]] */
implicit class BundleUpcastable[T <: Bundle](target: T) {
/** View a [[Bundle]] or [[Record]] as a parent type (upcast) */
def viewAsSupertype[V <: Bundle](proto: V)(implicit ev: SubTypeOf[T, V], sourceInfo: SourceInfo): V = {
- implicit val dataView = PartialDataView.mapping[T, V](
- _ => proto,
- {
- case (a, b) =>
- val aElts = a.elements
- val bElts = b.elements
- val bKeys = bElts.keySet
- val keys = aElts.keysIterator.filter(bKeys.contains)
- keys.map(k => aElts(k) -> bElts(k)).toSeq
- }
- )
+ implicit val dataView = PartialDataView.supertype[T, V](_ => proto)
target.viewAs[V]
}
}
diff --git a/docs/src/cookbooks/dataview.md b/docs/src/cookbooks/dataview.md
index ed969ca1..f970cfe4 100644
--- a/docs/src/cookbooks/dataview.md
+++ b/docs/src/cookbooks/dataview.md
@@ -12,6 +12,7 @@ section: "chisel3"
* [How do I connect a subset of Bundle fields?](#how-do-i-connect-a-subset-of-bundle-fields)
* [How do I view a Bundle as a parent type (superclass)?](#how-do-i-view-a-bundle-as-a-parent-type-superclass)
* [How do I view a Bundle as a parent type when the parent type is abstract (like a trait)?](#how-do-i-view-a-bundle-as-a-parent-type-when-the-parent-type-is-abstract-like-a-trait)
+ * [How can I use `.viewAs` instead of `.viewAsSupertype(type)`?](#how-can-i-use-viewas-instead-of-viewassupertypetype)
## How do I view a Data as a UInt or vice versa?
@@ -177,3 +178,37 @@ As indicated in the comment, abstract methods must still be implemented.
This is the same that happens when one writes `new Bundle {}`,
the curly braces create a new concrete subclass; however, because `Bundle` has no abstract methods,
the contents of the body can be empty.
+
+### How can I use `.viewAs` instead of `.viewAsSupertype(type)`?
+
+While `viewAsSupertype` is helpful for one-off casts, the need to provide a type template object
+each time can be onerous.
+Because of the subtyping relationship, you can use `PartialDataView.supertype` to create a
+`DataView` from a Bundle type to a parent type by just providing the function to construct an
+instance of the parent type from an instance of the child type.
+The mapping of corresponding fields is automatically determined by Chisel to be the fields defined
+in the supertype.
+
+```scala mdoc:silent:reset
+import chisel3._
+import chisel3.experimental.dataview._
+
+class Foo(x: Int) extends Bundle {
+ val foo = UInt(x.W)
+}
+class Bar(val x: Int) extends Foo(x) {
+ val bar = UInt(x.W)
+}
+// Define a DataView without having to specify the mapping!
+implicit val view = PartialDataView.supertype[Bar, Foo](b => new Foo(b.x))
+
+class MyModule extends Module {
+ val foo = IO(Input(new Foo(8)))
+ val bar = IO(Output(new Bar(8)))
+ bar.viewAs[Foo] := foo // bar.foo := foo.foo
+ bar.bar := 123.U // all fields need to be connected
+}
+```
+```scala mdoc:verilog
+chisel3.stage.ChiselStage.emitVerilog(new MyModule)
+```
diff --git a/src/test/scala/chiselTests/experimental/DataView.scala b/src/test/scala/chiselTests/experimental/DataView.scala
index ac8357f0..3673778b 100644
--- a/src/test/scala/chiselTests/experimental/DataView.scala
+++ b/src/test/scala/chiselTests/experimental/DataView.scala
@@ -177,6 +177,28 @@ class DataViewSpec extends ChiselFlatSpec {
chirrtl should include("fooOut.foo <= barIn.foo")
}
+ it should "be easy to make a PartialDataView viewing a Bundle as a Parent Bundle type" in {
+ class Foo(x: Int) extends Bundle {
+ val foo = UInt(x.W)
+ }
+ class Bar(val x: Int) extends Foo(x) {
+ val bar = UInt(x.W)
+ }
+ implicit val view = PartialDataView.supertype[Bar, Foo](b => new Foo(b.x))
+ class MyModule extends Module {
+ val fooIn = IO(Input(new Foo(8)))
+ val barOut = IO(Output(new Bar(8)))
+ barOut.viewAs[Foo] := fooIn
+
+ val barIn = IO(Input(new Bar(8)))
+ val fooOut = IO(Output(new Foo(8)))
+ fooOut := barIn.viewAs[Foo]
+ }
+ val chirrtl = ChiselStage.emitChirrtl(new MyModule)
+ chirrtl should include("barOut.foo <= fooIn.foo")
+ chirrtl should include("fooOut.foo <= barIn.foo")
+ }
+
it should "error if viewing a parent Bundle as a child Bundle type" in {
assertTypeError("""
class Foo extends Bundle {