summaryrefslogtreecommitdiff
path: root/src/test/scala/chiselTests/experimental/DataView.scala
diff options
context:
space:
mode:
Diffstat (limited to 'src/test/scala/chiselTests/experimental/DataView.scala')
-rw-r--r--src/test/scala/chiselTests/experimental/DataView.scala557
1 files changed, 0 insertions, 557 deletions
diff --git a/src/test/scala/chiselTests/experimental/DataView.scala b/src/test/scala/chiselTests/experimental/DataView.scala
deleted file mode 100644
index cefc893c..00000000
--- a/src/test/scala/chiselTests/experimental/DataView.scala
+++ /dev/null
@@ -1,557 +0,0 @@
-// See LICENSE for license details.
-
-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.{Analog, HWTuple2}
-import chisel3.stage.ChiselStage
-import chisel3.util.{Decoupled, DecoupledIO}
-
-object SimpleBundleDataView {
- class BundleA(val w: Int) extends Bundle {
- val foo = UInt(w.W)
- }
- class BundleB(val w: Int) extends Bundle {
- val bar = UInt(w.W)
- }
- implicit val v1 = DataView[BundleA, BundleB](a => new BundleB(a.w), _.foo -> _.bar)
- implicit val v2 = v1.invert(b => new BundleA(b.w))
-}
-
-object VecBundleDataView {
- class MyBundle extends Bundle {
- val foo = UInt(8.W)
- val bar = UInt(8.W)
- }
- implicit val v1: DataView[MyBundle, Vec[UInt]] = DataView(_ => Vec(2, UInt(8.W)), _.foo -> _(1), _.bar -> _(0))
- implicit val v2 = v1.invert(_ => new MyBundle)
-}
-
-object FlatDecoupledDataView {
- class FizzBuzz extends Bundle {
- val fizz = UInt(8.W)
- val buzz = UInt(8.W)
- }
- class FlatDecoupled extends Bundle {
- val valid = Output(Bool())
- val ready = Input(Bool())
- val fizz = Output(UInt(8.W))
- val buzz = Output(UInt(8.W))
- }
- implicit val view = DataView[FlatDecoupled, DecoupledIO[FizzBuzz]](
- _ => Decoupled(new FizzBuzz),
- _.valid -> _.valid,
- _.ready -> _.ready,
- _.fizz -> _.bits.fizz,
- _.buzz -> _.bits.buzz
- )
- implicit val view2 = view.invert(_ => new FlatDecoupled)
-}
-
-class DataViewSpec extends ChiselFlatSpec {
-
- behavior.of("DataView")
-
- it should "support simple Bundle viewing" in {
- import SimpleBundleDataView._
- class MyModule extends Module {
- val in = IO(Input(new BundleA(8)))
- val out = IO(Output(new BundleB(8)))
- out := in.viewAs[BundleB]
- }
- val chirrtl = ChiselStage.emitChirrtl(new MyModule)
- chirrtl should include("out.bar <= in.foo")
- }
-
- it should "be a bidirectional mapping" in {
- import SimpleBundleDataView._
- class MyModule extends Module {
- val in = IO(Input(new BundleA(8)))
- val out = IO(Output(new BundleB(8)))
- out.viewAs[BundleA] := in
- }
- val chirrtl = ChiselStage.emitChirrtl(new MyModule)
- chirrtl should include("out.bar <= in.foo")
- }
-
- it should "handle viewing UInts as UInts" in {
- class MyModule extends Module {
- val in = IO(Input(UInt(8.W)))
- val foo = IO(Output(UInt(8.W)))
- val bar = IO(Output(UInt(8.W)))
- foo := in.viewAs[UInt]
- bar.viewAs[UInt] := in
- }
- val chirrtl = ChiselStage.emitChirrtl(new MyModule)
- chirrtl should include("foo <= in")
- chirrtl should include("bar <= in")
- }
-
- it should "handle viewing Analogs as Analogs" in {
- class MyModule extends Module {
- val foo = IO(Analog(8.W))
- val bar = IO(Analog(8.W))
- foo <> bar.viewAs[Analog]
- }
- val chirrtl = ChiselStage.emitChirrtl(new MyModule)
- chirrtl should include("attach (foo, bar)")
- }
-
- it should "handle viewing Bundles as their same concrete type" in {
- class MyBundle extends Bundle {
- val foo = UInt(8.W)
- }
- class MyModule extends Module {
- val in = IO(Input(new MyBundle))
- val fizz = IO(Output(new MyBundle))
- val buzz = IO(Output(new MyBundle))
- fizz := in.viewAs[MyBundle]
- buzz.viewAs[MyBundle] := in
- }
- val chirrtl = ChiselStage.emitChirrtl(new MyModule)
- chirrtl should include("fizz <= in")
- chirrtl should include("buzz <= in")
- }
-
- it should "handle viewing Vecs as their same concrete type" in {
- class MyModule extends Module {
- val in = IO(Input(Vec(1, UInt(8.W))))
- val fizz = IO(Output(Vec(1, UInt(8.W))))
- val buzz = IO(Output(Vec(1, UInt(8.W))))
- fizz := in.viewAs[Vec[UInt]]
- buzz.viewAs[Vec[UInt]] := in
- }
- val chirrtl = ChiselStage.emitChirrtl(new MyModule)
- chirrtl should include("fizz <= in")
- chirrtl should include("buzz <= in")
- }
-
- it should "handle viewing Vecs as Bundles and vice versa" in {
- import VecBundleDataView._
- class MyModule extends Module {
- val in = IO(Input(new MyBundle))
- val out = IO(Output(Vec(2, UInt(8.W))))
- val out2 = IO(Output(Vec(2, UInt(8.W))))
- out := in.viewAs[Vec[UInt]]
- out2.viewAs[MyBundle] := in
- }
- val chirrtl = ChiselStage.emitChirrtl(new MyModule)
- chirrtl should include("out[0] <= in.bar")
- chirrtl should include("out[1] <= in.foo")
- chirrtl should include("out2[0] <= in.bar")
- chirrtl should include("out2[1] <= in.foo")
- }
-
- it should "work with bidirectional connections for nested types" in {
- import FlatDecoupledDataView._
- class MyModule extends Module {
- val enq = IO(Flipped(Decoupled(new FizzBuzz)))
- val deq = IO(new FlatDecoupled)
- val deq2 = IO(new FlatDecoupled)
- deq <> enq.viewAs[FlatDecoupled]
- deq2.viewAs[DecoupledIO[FizzBuzz]] <> enq
- }
- val chirrtl = ChiselStage.emitChirrtl(new MyModule)
- chirrtl should include("deq.valid <= enq.valid")
- chirrtl should include("enq.ready <= deq.ready")
- chirrtl should include("deq.fizz <= enq.bits.fizz")
- chirrtl should include("deq.buzz <= enq.bits.buzz")
- chirrtl should include("deq2.valid <= enq.valid")
- chirrtl should include("enq.ready <= deq2.ready")
- chirrtl should include("deq2.fizz <= enq.bits.fizz")
- chirrtl should include("deq2.buzz <= enq.bits.buzz")
- }
-
- it should "support viewing a Bundle as a Parent Bundle type" in {
- class Foo extends Bundle {
- val foo = UInt(8.W)
- }
- class Bar extends Foo {
- val bar = UInt(8.W)
- }
- class MyModule extends Module {
- val fooIn = IO(Input(new Foo))
- val barOut = IO(Output(new Bar))
- barOut.viewAsSupertype(new Foo) := fooIn
-
- val barIn = IO(Input(new Bar))
- val fooOut = IO(Output(new Foo))
- fooOut := barIn.viewAsSupertype(new Foo)
- }
- val chirrtl = ChiselStage.emitChirrtl(new MyModule)
- chirrtl should include("barOut.foo <= fooIn.foo")
- 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 {
- val foo = UInt(8.W)
- }
- class Bar extends Foo {
- val bar = UInt(8.W)
- }
- class MyModule extends Module {
- val barIn = IO(Input(new Bar))
- val fooOut = IO(Output(new Foo))
- fooOut.viewAs(new Bar) := barIn
- }
- """)
- }
-
- it should "work in UInt operations" in {
- class MyBundle extends Bundle {
- val value = UInt(8.W)
- }
- class MyModule extends Module {
- val a = IO(Input(UInt(8.W)))
- val b = IO(Input(new MyBundle))
- val cond = IO(Input(Bool()))
- val and, mux, bitsCat = IO(Output(UInt(8.W)))
- // Chisel unconditionally emits a node, so name it at least
- val x = a.viewAs[UInt] & b.viewAs[MyBundle].value
- and.viewAs[UInt] := x
-
- val y = Mux(cond.viewAs[Bool], a.viewAs[UInt], b.value.viewAs[UInt])
- mux.viewAs[UInt] := y
-
- // TODO should we have a macro so that we don't need .apply?
- val aBits = a.viewAs[UInt].apply(3, 0)
- val bBits = b.viewAs[MyBundle].value(3, 0)
- val abCat = aBits.viewAs[UInt] ## bBits.viewAs[UInt]
- bitsCat := abCat
- }
- val chirrtl = ChiselStage.emitChirrtl(new MyModule)
- val expected = List(
- "node x = and(a, b.value)",
- "and <= x",
- "node y = mux(cond, a, b.value)",
- "mux <= y",
- "node aBits = bits(a, 3, 0)",
- "node bBits = bits(b.value, 3, 0)",
- "node abCat = cat(aBits, bBits)",
- "bitsCat <= abCat"
- )
- for (line <- expected) {
- chirrtl should include(line)
- }
- }
-
- it should "support .asUInt of Views" in {
- import VecBundleDataView._
- class MyModule extends Module {
- val barIn = IO(Input(new MyBundle))
- val fooOut = IO(Output(UInt()))
- val cat = barIn.viewAs[Vec[UInt]].asUInt
- fooOut := cat
- }
- val chirrtl = ChiselStage.emitChirrtl(new MyModule)
- chirrtl should include("node cat = cat(barIn.foo, barIn.bar)")
- chirrtl should include("fooOut <= cat")
- }
-
- it should "be composable" in {
- // Given DataView[A, B] and DataView[B, C], derive DataView[A, C]
- class Foo(val foo: UInt) extends Bundle
- class Bar(val bar: UInt) extends Bundle
- class Fizz(val fizz: UInt) extends Bundle
-
- implicit val foo2bar = DataView[Foo, Bar](f => new Bar(chiselTypeClone(f.foo)), _.foo -> _.bar)
- implicit val bar2fizz = DataView[Bar, Fizz](b => new Fizz(chiselTypeClone(b.bar)), _.bar -> _.fizz)
-
- implicit val foo2fizz: DataView[Foo, Fizz] = foo2bar.andThen(bar2fizz)
-
- class MyModule extends Module {
- val a, b = IO(Input(new Foo(UInt(8.W))))
- val y, z = IO(Output(new Fizz(UInt(8.W))))
- y := a.viewAs[Fizz]
- z := b.viewAs[Bar].viewAs[Fizz]
- }
- val chirrtl = ChiselStage.emitChirrtl(new MyModule)
- chirrtl should include("y.fizz <= a.foo")
- chirrtl should include("z.fizz <= b.foo")
- }
-
- 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)))
- // 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)
- verilog should include("assign y = sel ? a : c;")
- verilog should include("assign z = sel ? b : d;")
- }
-
- // This example should be turned into a built-in feature
- it should "enable viewing Seqs as Vecs" in {
-
- class MyModule extends Module {
- val a, b, c = IO(Input(UInt(8.W)))
- val x, y, z = IO(Output(UInt(8.W)))
- Seq(x, y, z) := VecInit(a, b, c)
- }
- // Verilog instead of CHIRRTL because the optimizations make it much prettier
- val verilog = ChiselStage.emitVerilog(new MyModule)
- verilog should include("assign x = a;")
- verilog should include("assign y = b;")
- verilog should include("assign z = c;")
- }
-
- it should "support recursive composition of views" 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)))
-
- // A little annoying that we need the type annotation on VecInit to get the implicit conversion to work
- // Note that one can just use the Seq on the RHS so there is an alternative (may lack discoverability)
- // We could also overload `VecInit` instead of relying on the implicit conversion
- Seq((w, x), (y, z)) := VecInit[HWTuple2[UInt, UInt]]((a, b), (c, d))
- }
- val verilog = ChiselStage.emitVerilog(new MyModule)
- verilog should include("assign w = a;")
- verilog should include("assign x = b;")
- verilog should include("assign y = c;")
- verilog should include("assign z = d;")
- }
-
- it should "support dynamic indexing for Vec identity views" in {
- class MyModule extends Module {
- val dataIn = IO(Input(UInt(8.W)))
- val addr = IO(Input(UInt(2.W)))
- val dataOut = IO(Output(UInt(8.W)))
-
- val vec = RegInit(0.U.asTypeOf(Vec(4, UInt(8.W))))
- val view = vec.viewAs[Vec[UInt]]
- // Dynamic indexing is more of a "generator" in Chisel3 than an individual node
- // This style is not recommended, this is just testing the behavior
- val selected = view(addr)
- selected := dataIn
- dataOut := selected
- }
- val chirrtl = ChiselStage.emitChirrtl(new MyModule)
- chirrtl should include("vec[addr] <= dataIn")
- chirrtl should include("dataOut <= vec[addr]")
- }
-
- it should "support dynamic indexing for Vecs that correspond 1:1 in a view" in {
- class MyBundle extends Bundle {
- val foo = Vec(4, UInt(8.W))
- val bar = UInt(2.W)
- }
- implicit val myView = DataView[(Vec[UInt], UInt), MyBundle](
- _ => new MyBundle,
- _._1 -> _.foo,
- _._2 -> _.bar
- )
- class MyModule extends Module {
- val dataIn = IO(Input(UInt(8.W)))
- val addr = IO(Input(UInt(2.W)))
- val dataOut = IO(Output(UInt(8.W)))
-
- val vec = RegInit(0.U.asTypeOf(Vec(4, UInt(8.W))))
- val addrReg = Reg(UInt(2.W))
- val view = (vec, addrReg).viewAs[MyBundle]
- // Dynamic indexing is more of a "generator" in Chisel3 than an individual node
- // This style is not recommended, this is just testing the behavior
- val selected = view.foo(view.bar)
- view.bar := addr
- selected := dataIn
- dataOut := selected
- }
- val chirrtl = ChiselStage.emitChirrtl(new MyModule)
- chirrtl should include("vec[addrReg] <= dataIn")
- chirrtl should include("dataOut <= vec[addrReg]")
- }
-
- it should "error if you try to dynamically index a Vec view that does not correspond to a Vec target" in {
- class MyModule extends Module {
- val inA, inB = IO(Input(UInt(8.W)))
- val outA, outB = IO(Output(UInt(8.W)))
- val idx = IO(Input(UInt(1.W)))
-
- val a, b, c, d = RegInit(0.U)
-
- // Dynamic indexing is more of a "generator" in Chisel3 than an individual node
- // This style is not recommended, this is just testing the behavior
- val selected = Seq((a, b), (c, d)).apply(idx)
- selected := (inA, inB)
- (outA, outB) := selected
- }
- (the[InvalidViewException] thrownBy {
- ChiselStage.emitChirrtl(new MyModule)
- }).getMessage should include("Dynamic indexing of Views is not yet supported")
- }
-
- it should "error if the mapping is non-total in the view" in {
- class MyBundle(val foo: UInt, val bar: UInt) extends Bundle
- implicit val dv = DataView[UInt, MyBundle](_ => new MyBundle(UInt(), UInt()), _ -> _.bar)
- class MyModule extends Module {
- val tpe = new MyBundle(UInt(8.W), UInt(8.W))
- val in = IO(Input(UInt(8.W)))
- val out = IO(Output(tpe))
- out := in.viewAs[MyBundle]
- }
- val err = the[InvalidViewException] thrownBy (ChiselStage.emitVerilog(new MyModule))
- err.toString should include("View field '_.foo' is missing")
- }
-
- it should "error if the mapping is non-total in the target" in {
- implicit val dv = DataView[(UInt, UInt), UInt](_ => UInt(), _._1 -> _)
- class MyModule extends Module {
- val a, b = IO(Input(UInt(8.W)))
- val out = IO(Output(UInt(8.W)))
- out := (a, b).viewAs[UInt]
- }
- val err = the[InvalidViewException] thrownBy (ChiselStage.emitVerilog(new MyModule))
- err.toString should include("Target field '_._2' is missing")
- }
-
- it should "error if the mapping contains Data that are not part of the Target" in {
- class BundleA extends Bundle {
- val foo = UInt(8.W)
- }
- class BundleB extends Bundle {
- val fizz = UInt(8.W)
- val buzz = UInt(8.W)
- }
- implicit val dv = DataView[BundleA, BundleB](_ => new BundleB, _.foo -> _.fizz, (_, b) => (3.U, b.buzz))
- class MyModule extends Module {
- val in = IO(Input(new BundleA))
- val out = IO(Output(new BundleB))
- out := in.viewAs[BundleB]
- }
- val err = the[InvalidViewException] thrownBy (ChiselStage.emitVerilog(new MyModule))
- err.toString should include("View mapping must only contain Elements within the Target")
- }
-
- it should "error if the mapping contains Data that are not part of the View" in {
- class BundleA extends Bundle {
- val foo = UInt(8.W)
- }
- class BundleB extends Bundle {
- val fizz = UInt(8.W)
- val buzz = UInt(8.W)
- }
- implicit val dv = DataView[BundleA, BundleB](_ => new BundleB, _.foo -> _.fizz, (_, b) => (3.U, b.buzz))
- implicit val dv2 = dv.invert(_ => new BundleA)
- class MyModule extends Module {
- val in = IO(Input(new BundleA))
- val out = IO(Output(new BundleB))
- out.viewAs[BundleA] := in
- }
- val err = the[InvalidViewException] thrownBy (ChiselStage.emitVerilog(new MyModule))
- err.toString should include("View mapping must only contain Elements within the View")
- }
-
- it should "error if a view has a width that does not match the target" in {
- class BundleA extends Bundle {
- val foo = UInt(8.W)
- }
- class BundleB extends Bundle {
- val bar = UInt(4.W)
- }
- implicit val dv = DataView[BundleA, BundleB](_ => new BundleB, _.foo -> _.bar)
- class MyModule extends Module {
- val in = IO(Input(new BundleA))
- val out = IO(Output(new BundleB))
- out := in.viewAs[BundleB]
- }
- val err = the[InvalidViewException] thrownBy ChiselStage.emitChirrtl(new MyModule)
- val expected = """View field _\.bar UInt<4> has width <4> that is incompatible with target value .+'s width <8>""".r
- (err.getMessage should fullyMatch).regex(expected)
- }
-
- it should "error if a view has a known width when the target width is unknown" in {
- class BundleA extends Bundle {
- val foo = UInt()
- }
- class BundleB extends Bundle {
- val bar = UInt(4.W)
- }
- implicit val dv = DataView[BundleA, BundleB](_ => new BundleB, _.foo -> _.bar)
- class MyModule extends Module {
- val in = IO(Input(new BundleA))
- val out = IO(Output(new BundleB))
- out := in.viewAs[BundleB]
- }
- val err = the[InvalidViewException] thrownBy ChiselStage.emitChirrtl(new MyModule)
- val expected =
- """View field _\.bar UInt<4> has width <4> that is incompatible with target value .+'s width <unknown>""".r
- (err.getMessage should fullyMatch).regex(expected)
- }
-
- it should "support invalidation" in {
- class MyModule extends Module {
- val a, b, c, d, e, f = IO(Output(UInt(8.W)))
- val foo = (a, b).viewAs
- val bar = (c, d).viewAs
- val fizz = (e, f).viewAs
- foo := DontCare
- bar <> DontCare
- fizz._1 := DontCare
- fizz._2 <> DontCare
- }
-
- val chirrtl = ChiselStage.emitChirrtl(new MyModule)
- val expected = ('a' to 'f').map(c => s"$c is invalid")
- for (line <- expected) {
- chirrtl should include(line)
- }
- }
-
- behavior.of("PartialDataView")
-
- it should "still error if the mapping is non-total in the view" in {
- class MyBundle(val foo: UInt, val bar: UInt) extends Bundle
- implicit val dv = PartialDataView[UInt, MyBundle](_ => new MyBundle(UInt(), UInt()), _ -> _.bar)
- class MyModule extends Module {
- val in = IO(Input(UInt(8.W)))
- val out = IO(Output(new MyBundle(UInt(8.W), UInt(8.W))))
- out := in.viewAs[MyBundle]
- }
- val err = the[InvalidViewException] thrownBy (ChiselStage.emitVerilog(new MyModule))
- err.toString should include("View field '_.foo' is missing")
- }
-
- it should "NOT error if the mapping is non-total in the target" in {
- implicit val dv = PartialDataView[(UInt, UInt), UInt](_ => UInt(), _._2 -> _)
- class MyModule extends Module {
- val a, b = IO(Input(UInt(8.W)))
- val out = IO(Output(UInt(8.W)))
- out := (a, b).viewAs[UInt]
- }
- val verilog = ChiselStage.emitVerilog(new MyModule)
- verilog should include("assign out = b;")
- }
-}