1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
|
// See LICENSE for license details.
package chiselTests.experimental
import chisel3._
import chisel3.experimental.dataview._
import chisel3.experimental.{ChiselAnnotation, annotate}
import chisel3.stage.ChiselStage
import chiselTests.ChiselFlatSpec
object DataViewTargetSpec {
import firrtl.annotations._
private case class DummyAnno(target: ReferenceTarget, id: Int) extends SingleTargetAnnotation[ReferenceTarget] {
override def duplicate(n: ReferenceTarget) = this.copy(target = n)
}
private def mark(d: Data, id: Int) = annotate(new ChiselAnnotation {
override def toFirrtl: Annotation = DummyAnno(d.toTarget, id)
})
private def markAbs(d: Data, id: Int) = annotate(new ChiselAnnotation {
override def toFirrtl: Annotation = DummyAnno(d.toAbsoluteTarget, id)
})
}
class DataViewTargetSpec extends ChiselFlatSpec {
import DataViewTargetSpec._
private val checks: Seq[Data => String] = Seq(
_.toTarget.toString,
_.toAbsoluteTarget.toString,
_.instanceName,
_.pathName,
_.parentPathName,
_.parentModName,
)
// Check helpers
private def checkAll(impl: Data, refs: String*): Unit = {
refs.size should be (checks.size)
for ((check, value) <- checks.zip(refs)) {
check(impl) should be (value)
}
}
private def checkSameAs(impl: Data, refs: Data*): Unit =
for (ref <- refs) {
checkAll(impl, checks.map(_(ref)):_*)
}
behavior of "DataView Naming"
it should "support views of Elements" in {
class MyChild extends Module {
val out = IO(Output(UInt(8.W)))
val insideView = out.viewAs[UInt]
out := 0.U
}
class MyParent extends Module {
val out = IO(Output(UInt(8.W)))
val inst = Module(new MyChild)
out := inst.out
}
val m = elaborateAndGetModule(new MyParent)
val outsideView = m.inst.out.viewAs[UInt]
checkSameAs(m.inst.out, m.inst.insideView, outsideView)
}
it should "support 1:1 mappings of Aggregates and their children" in {
class MyBundle extends Bundle {
val foo = UInt(8.W)
val bars = Vec(2, UInt(8.W))
}
implicit val dv = DataView[MyBundle, Vec[UInt]](_ => Vec(3, UInt(8.W)), _.foo -> _(0), _.bars(0) -> _(1), _.bars(1) -> _(2))
class MyChild extends Module {
val out = IO(Output(new MyBundle))
val outView = out.viewAs[Vec[UInt]] // Note different type
val outFooView = out.foo.viewAs[UInt]
val outBarsView = out.bars.viewAs[Vec[UInt]]
val outBars0View = out.bars(0).viewAs[UInt]
out := 0.U.asTypeOf(new MyBundle)
}
class MyParent extends Module {
val out = IO(Output(new MyBundle))
val inst = Module(new MyChild)
out := inst.out
}
val m = elaborateAndGetModule(new MyParent)
val outView = m.inst.out.viewAs[Vec[UInt]]// Note different type
val outFooView = m.inst.out.foo.viewAs[UInt]
val outBarsView = m.inst.out.bars.viewAs[Vec[UInt]]
val outBars0View = m.inst.out.bars(0).viewAs[UInt]
checkSameAs(m.inst.out, m.inst.outView, outView)
checkSameAs(m.inst.out.foo, m.inst.outFooView, m.inst.outView(0), outFooView, outView(0))
checkSameAs(m.inst.out.bars, m.inst.outBarsView, outBarsView)
checkSameAs(m.inst.out.bars(0), m.inst.outBars0View, outBars0View, m.inst.outView(1), outView(1),
m.inst.outBarsView(0), outBarsView(0))
}
// Ideally this would work 1:1 but that requires changing the binding
it should "support annotation renaming of Aggregate children of Aggregate views" in {
class MyBundle extends Bundle {
val foo = Vec(2, UInt(8.W))
}
class MyChild extends Module {
val out = IO(Output(new MyBundle))
val outView = out.viewAs[MyBundle]
mark(out.foo, 0)
mark(outView.foo, 1)
markAbs(out.foo, 2)
markAbs(outView, 3)
out := 0.U.asTypeOf(new MyBundle)
}
class MyParent extends Module {
val out = IO(Output(new MyBundle))
val inst = Module(new MyChild)
out := inst.out
}
val (_, annos) = getFirrtlAndAnnos(new MyParent)
val pairs = annos.collect { case DummyAnno(t, idx) => (idx, t.toString) }.sortBy(_._1)
val expected = Seq(
0 -> "~MyParent|MyChild>out.foo",
// The child of the view that was itself an Aggregate got split because 1:1 is lacking here
1 -> "~MyParent|MyChild>out.foo[0]",
1 -> "~MyParent|MyChild>out.foo[1]",
2 -> "~MyParent|MyParent/inst:MyChild>out.foo",
3 -> "~MyParent|MyParent/inst:MyChild>out"
)
pairs should equal (expected)
}
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))
}
// Note that each use of a Tuple as Data causes an implicit conversion creating a View
class MyChild extends Module {
val io = IO(new MyBundle)
(io.c, io.d) := (io.a, io.b)
// The type annotations create the views via the implicit conversion
val view1: Data = (io.a, io.b)
val view2: Data = (io.c, io.d)
mark(view1, 0)
mark(view2, 1)
markAbs(view1, 2)
markAbs(view2, 3)
mark((io.b, io.d), 4) // Mix it up for fun
}
class MyParent extends Module {
val io = IO(new MyBundle)
val inst = Module(new MyChild)
io <> inst.io
}
val (_, annos) = getFirrtlAndAnnos(new MyParent)
val pairs = annos.collect { case DummyAnno(t, idx) => (idx, t.toString) }.sorted
val expected = Seq(
0 -> "~MyParent|MyChild>io.a",
0 -> "~MyParent|MyChild>io.b",
1 -> "~MyParent|MyChild>io.c",
1 -> "~MyParent|MyChild>io.d",
2 -> "~MyParent|MyParent/inst:MyChild>io.a",
2 -> "~MyParent|MyParent/inst:MyChild>io.b",
3 -> "~MyParent|MyParent/inst:MyChild>io.c",
3 -> "~MyParent|MyParent/inst:MyChild>io.d",
4 -> "~MyParent|MyChild>io.b",
4 -> "~MyParent|MyChild>io.d",
)
pairs should equal (expected)
}
}
|