@@ -15,11 +15,58 @@ import chisel3.internal.sourceinfo._
15
15
* of) other Data objects.
16
16
*/
17
17
sealed abstract class Aggregate extends Data {
18
+ private [chisel3] override def bind (target : Binding , parentDirection : UserDirection ) {
19
+ binding = target
20
+
21
+ val resolvedDirection = UserDirection .fromParent(parentDirection, userDirection)
22
+ for (child <- getElements) {
23
+ child.bind(ChildBinding (this ), resolvedDirection)
24
+ }
25
+
26
+ // Check that children obey the directionality rules.
27
+ val childDirections = getElements.map(_.direction).toSet
28
+ direction = if (childDirections == Set ()) { // Sadly, Scala can't do set matching
29
+ // If empty, use my assigned direction
30
+ resolvedDirection match {
31
+ case UserDirection .Unspecified | UserDirection .Flip => ActualDirection .Unspecified
32
+ case UserDirection .Output => ActualDirection .Output
33
+ case UserDirection .Input => ActualDirection .Input
34
+ }
35
+ } else if (childDirections == Set (ActualDirection .Unspecified )) {
36
+ ActualDirection .Unspecified
37
+ } else if (childDirections == Set (ActualDirection .Input )) {
38
+ ActualDirection .Input
39
+ } else if (childDirections == Set (ActualDirection .Output )) {
40
+ ActualDirection .Output
41
+ } else if (childDirections subsetOf
42
+ Set (ActualDirection .Output , ActualDirection .Input ,
43
+ ActualDirection .Bidirectional (ActualDirection .Default ),
44
+ ActualDirection .Bidirectional (ActualDirection .Flipped ))) {
45
+ resolvedDirection match {
46
+ case UserDirection .Unspecified => ActualDirection .Bidirectional (ActualDirection .Default )
47
+ case UserDirection .Flip => ActualDirection .Bidirectional (ActualDirection .Flipped )
48
+ case _ => throw new RuntimeException (" Unexpected forced Input / Output" )
49
+ }
50
+ } else {
51
+ this match {
52
+ // Anything flies in compatibility mode
53
+ case t : Record if ! t.compileOptions.dontAssumeDirectionality => resolvedDirection match {
54
+ case UserDirection .Unspecified => ActualDirection .Bidirectional (ActualDirection .Default )
55
+ case UserDirection .Flip => ActualDirection .Bidirectional (ActualDirection .Flipped )
56
+ case _ => ActualDirection .Bidirectional (ActualDirection .Default )
57
+ }
58
+ case _ =>
59
+ val childWithDirections = getElements zip getElements.map(_.direction)
60
+ throw Binding .MixedDirectionAggregateException (s " Aggregate ' $this' can't have elements that are both directioned and undirectioned: $childWithDirections" )
61
+ }
62
+ }
63
+ }
64
+
18
65
/** Returns a Seq of the immediate contents of this Aggregate, in order.
19
66
*/
20
67
def getElements : Seq [Data ]
21
68
22
- private [core ] def width : Width = getElements.map(_.width).foldLeft(0 .W )(_ + _)
69
+ private [chisel3 ] def width : Width = getElements.map(_.width).foldLeft(0 .W )(_ + _)
23
70
private [core] def legacyConnect (that : Data )(implicit sourceInfo : SourceInfo ): Unit =
24
71
pushCommand(BulkConnect (sourceInfo, this .lref, that.lref))
25
72
@@ -68,25 +115,21 @@ object Vec {
68
115
69
116
// Check that types are homogeneous. Width mismatch for Elements is safe.
70
117
require(! elts.isEmpty)
118
+ elts.foreach(requireIsHardware(_, " vec element" ))
71
119
72
120
val vec = Wire (new Vec (cloneSupertype(elts, " Vec" ), elts.length))
73
121
74
- def doConnect (sink : T , source : T ) = {
75
- // TODO: this looks bad, and should feel bad. Replace with a better abstraction.
76
- // NOTE: Must use elts.head instead of vec.sample_element because vec.sample_element has
77
- // WireBinding which does not have a direction
78
- val hasDirectioned = elts.head match {
79
- case t : Aggregate => t.flatten.exists(_.dir != Direction .Unspecified )
80
- case t : Element => t.dir != Direction .Unspecified
81
- }
82
- if (hasDirectioned) {
83
- sink bulkConnect source
84
- } else {
85
- sink connect source
86
- }
87
- }
88
- for ((v, e) <- vec zip elts) {
89
- doConnect(v, e)
122
+ // TODO: try to remove the logic for this mess
123
+ elts.head.direction match {
124
+ case ActualDirection .Input | ActualDirection .Output | ActualDirection .Unspecified =>
125
+ // When internal wires are involved, driver / sink must be specified explicitly, otherwise
126
+ // the system is unable to infer which is driver / sink
127
+ (vec zip elts).foreach(x => x._1 := x._2)
128
+ case ActualDirection .Bidirectional (_) =>
129
+ // For bidirectional, must issue a bulk connect so subelements are resolved correctly.
130
+ // Bulk connecting two wires may not succeed because Chisel frontend does not infer
131
+ // directions.
132
+ (vec zip elts).foreach(x => x._1 <> x._2)
90
133
}
91
134
vec
92
135
}
@@ -186,7 +229,7 @@ sealed class Vec[T <: Data] private (gen: => T, val length: Int)
186
229
*
187
230
* Needed specifically for the case when the Vec is length 0.
188
231
*/
189
- private [core ] val sample_element : T = gen
232
+ private [chisel3 ] val sample_element : T = gen
190
233
191
234
// allElements current includes sample_element
192
235
// This is somewhat weird although I think the best course of action here is
@@ -226,16 +269,25 @@ sealed class Vec[T <: Data] private (gen: => T, val length: Int)
226
269
override def apply (p : UInt ): T = macro CompileOptionsTransform .pArg
227
270
228
271
def do_apply (p : UInt )(implicit compileOptions : CompileOptions ): T = {
229
- Binding .checkSynthesizable(p , s " 'p' ( $p ) " )
272
+ requireIsHardware(p, " vec index " )
230
273
val port = gen
231
- val i = Vec .truncateIndex(p, length)(UnlocatableSourceInfo , compileOptions)
232
- port.setRef(this , i)
233
274
234
- // Bind each element of port to being whatever the base type is
235
- // Using the head element as the sample_element
236
- for ((port_elem, model_elem) <- port.allElements zip sample_element.allElements) {
237
- port_elem.binding = model_elem.binding
275
+ // Reconstruct the resolvedDirection (in Aggregate.bind), since it's not stored.
276
+ // It may not be exactly equal to that value, but the results are the same.
277
+ val reconstructedResolvedDirection = direction match {
278
+ case ActualDirection .Input => UserDirection .Input
279
+ case ActualDirection .Output => UserDirection .Output
280
+ case ActualDirection .Bidirectional (ActualDirection .Default ) | ActualDirection .Unspecified =>
281
+ UserDirection .Unspecified
282
+ case ActualDirection .Bidirectional (ActualDirection .Flipped ) => UserDirection .Flip
238
283
}
284
+ // TODO port technically isn't directly child of this data structure, but the result of some
285
+ // muxes / demuxes. However, this does make access consistent with the top-level bindings.
286
+ // Perhaps there's a cleaner way of accomplishing this...
287
+ port.bind(ChildBinding (this ), reconstructedResolvedDirection)
288
+
289
+ val i = Vec .truncateIndex(p, length)(UnlocatableSourceInfo , compileOptions)
290
+ port.setRef(this , i)
239
291
240
292
port
241
293
}
@@ -256,7 +308,6 @@ sealed class Vec[T <: Data] private (gen: => T, val length: Int)
256
308
new Vec (gen.cloneType, length).asInstanceOf [this .type ]
257
309
}
258
310
259
- private [chisel3] def toType : String = s " ${sample_element.toType}[ $length] "
260
311
override def getElements : Seq [Data ] =
261
312
(0 until length).map(apply(_))
262
313
@@ -384,14 +435,6 @@ abstract class Record(private[chisel3] implicit val compileOptions: CompileOptio
384
435
/** Name for Pretty Printing */
385
436
def className : String = this .getClass.getSimpleName
386
437
387
- private [chisel3] def toType = {
388
- def eltPort (elt : Data ): String = {
389
- val flipStr : String = if (Data .isFirrtlFlipped(elt)) " flip " else " "
390
- s " ${flipStr}${elt.getRef.name} : ${elt.toType}"
391
- }
392
- elements.toIndexedSeq.reverse.map(e => eltPort(e._2)).mkString(" {" , " , " , " }" )
393
- }
394
-
395
438
private [core] override def typeEquivalent (that : Data ): Boolean = that match {
396
439
case that : Record =>
397
440
this .getClass == that.getClass &&
0 commit comments