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
170
|
// SPDX-License-Identifier: Apache-2.0
package firrtl
package annotations
import firrtl.options.StageUtils
import org.json4s.JValue
import scala.collection.Traversable
case class AnnotationException(message: String) extends Exception(message)
/** Base type of auxiliary information */
trait Annotation extends Product {
/** Update the target based on how signals are renamed */
def update(renames: RenameMap): Seq[Annotation]
/** Optional pretty print
*
* @note rarely used
*/
def serialize: String = this.toString
/** Recurses through ls to find all [[Target]] instances
* @param ls
* @return
*/
private def extractComponents(ls: Traversable[?]): Traversable[Target] = {
ls.flatMap {
case c: Target => Seq(c)
case x: scala.collection.Traversable[_] => extractComponents(x)
case o: Product => extractComponents(o.productIterator.toIterable)
case _ => Seq()
}
}
/** Returns all [[firrtl.annotations.Target Target]] members in this annotation
* @return
*/
def getTargets: Seq[Target] = extractComponents(productIterator.toIterable).toSeq
/** Returns a deduplicable representation of this [[Annotation]]: a 3-tuple of the
* deduplicated annotation's "dedup key", the deduplicated [[Annotation]], and the
* [[firrtl.annotations.ReferenceTarget ReferenceTarget]](s) to the annotated objects.
*
* If two absolute instances of this [[Annotation]] would deduplicate to the same
* local form, both of their "dedup key"s must be equivalent.
*
* A deduplication key is typically taken to be a 2-tuple of the pathless target and
* the annotation's value.
*
* Returning None signifies this annotation will not deduplicate.
* @return
*/
private[firrtl] def dedup: Option[(Any, Annotation, ReferenceTarget)] = None
}
/** If an Annotation does not target any [[Named]] thing in the circuit, then all updates just
* return the Annotation itself
*/
trait NoTargetAnnotation extends Annotation {
def update(renames: RenameMap): Seq[NoTargetAnnotation] = Seq(this)
override def getTargets: Seq[Target] = Seq.empty
}
/** An Annotation that targets a single [[Named]] thing */
trait SingleTargetAnnotation[T <: Named] extends Annotation {
val target: T
// we can implement getTargets more efficiently since we know that we have exactly one target
override def getTargets: Seq[Target] = Seq(target)
/** Create another instance of this Annotation */
def duplicate(n: T): Annotation
// This mess of @unchecked and try-catch is working around the fact that T is unknown due to type
// erasure. We cannot that newTarget is of type T, but a CastClassException will be thrown upon
// invoking duplicate if newTarget cannot be cast to T (only possible in the concrete subclass)
def update(renames: RenameMap): Seq[Annotation] = {
target match {
case c: Target =>
val x = renames.get(c)
x.map(newTargets => newTargets.map(t => duplicate(t.asInstanceOf[T]))).getOrElse(List(this))
case from: Named =>
val ret = renames.get(Target.convertNamed2Target(target))
ret
.map(_.map { newT =>
val result = newT match {
case c: InstanceTarget => ModuleName(c.ofModule, CircuitName(c.circuit))
case c: IsMember =>
val local = Target.referringModule(c)
c.setPathTarget(local)
case c: CircuitTarget => c.toNamed
case other => throw Target.NamedException(s"Cannot convert $other to [[Named]]")
}
(Target.convertTarget2Named(result): @unchecked) match {
case newTarget: T @unchecked =>
try {
duplicate(newTarget)
} catch {
case _: java.lang.ClassCastException =>
val msg = s"${this.getClass.getName} target ${target.getClass.getName} " +
s"cannot be renamed to ${newTarget.getClass}"
throw AnnotationException(msg)
}
}
})
.getOrElse(List(this))
}
}
}
/** [[MultiTargetAnnotation]] keeps the renamed targets grouped within a single annotation. */
trait MultiTargetAnnotation extends Annotation {
/** Contains a nested sequence of [[firrtl.annotations.Target Target]]
*
* Each inner Seq should contain a single element. For example:
* {{{
* def targets = Seq(Seq(foo), Seq(bar))
* }}}
*/
def targets: Seq[Seq[Target]]
override def getTargets: Seq[Target] = targets.flatten
/** Create another instance of this Annotation
*
* The inner Seqs correspond to the renames of the inner Seqs of targets
*/
def duplicate(n: Seq[Seq[Target]]): Annotation
/** Assume [[RenameMap]] is `Map(TargetA -> Seq(TargetA1, TargetA2, TargetA3), TargetB -> Seq(TargetB1, TargetB2))`
* in the update, this Annotation is still one annotation, but the contents are renamed in the below form
* Seq(Seq(TargetA1, TargetA2, TargetA3), Seq(TargetB1, TargetB2), Seq(TargetC))
*/
def update(renames: RenameMap): Seq[Annotation] = Seq(duplicate(targets.map(ts => ts.flatMap(renames(_)))))
private def crossJoin[T](list: Seq[Seq[T]]): Seq[Seq[T]] =
list match {
case Nil => Nil
case x :: Nil => x.map(Seq(_))
case x :: xs =>
val xsJoin = crossJoin(xs)
for {
i <- x
j <- xsJoin
} yield {
Seq(i) ++ j
}
}
/** Assume [[RenameMap]] is `Map(TargetA -> Seq(TargetA1, TargetA2, TargetA3), TargetB -> Seq(TargetB1, TargetB2))`
* After flat, this Annotation will be flat to the [[AnnotationSeq]] in the below form
* Seq(Seq(TargetA1), Seq(TargetB1), Seq(TargetC)); Seq(Seq(TargetA1), Seq(TargetB2), Seq(TargetC))
* Seq(Seq(TargetA2), Seq(TargetB1), Seq(TargetC)); Seq(Seq(TargetA2), Seq(TargetB2), Seq(TargetC))
* Seq(Seq(TargetA3), Seq(TargetB1), Seq(TargetC)); Seq(Seq(TargetA3), Seq(TargetB2), Seq(TargetC))
*/
def flat(): AnnotationSeq = crossJoin(targets).map(r => duplicate(r.map(Seq(_))))
}
object Annotation
case class DeletedAnnotation(xFormName: String, anno: Annotation) extends NoTargetAnnotation {
override def serialize: String = s"""DELETED by $xFormName\n${anno.serialize}"""
}
case class UnrecognizedAnnotation(underlying: JValue) extends NoTargetAnnotation
|