aboutsummaryrefslogtreecommitdiff
path: root/src/main/scala/firrtl/annotations/Annotation.scala
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/scala/firrtl/annotations/Annotation.scala')
-rw-r--r--src/main/scala/firrtl/annotations/Annotation.scala71
1 files changed, 52 insertions, 19 deletions
diff --git a/src/main/scala/firrtl/annotations/Annotation.scala b/src/main/scala/firrtl/annotations/Annotation.scala
index 4b0591bf..62c2b335 100644
--- a/src/main/scala/firrtl/annotations/Annotation.scala
+++ b/src/main/scala/firrtl/annotations/Annotation.scala
@@ -5,11 +5,15 @@ package annotations
import net.jcazevedo.moultingyaml._
import firrtl.annotations.AnnotationYamlProtocol._
+import firrtl.Utils.throwInternalError
+
+import scala.collection.mutable
case class AnnotationException(message: String) extends Exception(message)
/** Base type of auxiliary information */
-trait Annotation {
+trait Annotation extends Product {
+
/** Update the target based on how signals are renamed */
def update(renames: RenameMap): Seq[Annotation]
@@ -18,13 +22,29 @@ trait Annotation {
* @note In [[logger.LogLevel.Debug]] this is called on every Annotation after every Transform
*/
def serialize: String = this.toString
+
+ /** Recurses through ls to find all [[Target]] instances
+ * @param ls
+ * @return
+ */
+ private def extractComponents(ls: scala.collection.Traversable[_]): Seq[Target] = {
+ ls.collect {
+ case c: Target => Seq(c)
+ case ls: scala.collection.Traversable[_] => extractComponents(ls)
+ }.foldRight(Seq.empty[Target])((seq, c) => c ++ seq)
+ }
+
+ /** Returns all [[Target]] members in this annotation
+ * @return
+ */
+ def getTargets: Seq[Target] = extractComponents(productIterator.toSeq)
}
/** 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(this)
+ def update(renames: RenameMap): Seq[NoTargetAnnotation] = Seq(this)
}
/** An Annotation that targets a single [[Named]] thing */
@@ -37,18 +57,27 @@ trait SingleTargetAnnotation[T <: Named] extends 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] =
- renames.get(target).map(_.map(newT => (newT: @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))
+ 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 _: Named =>
+ val ret = renames.get(Target.convertNamed2Target(target))
+ ret.map(_.map(newT => Target.convertTarget2Named(newT: @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))
+ }
+ }
}
@deprecated("Just extend NoTargetAnnotation", "1.1")
@@ -58,7 +87,7 @@ trait SingleStringAnnotation extends NoTargetAnnotation {
object Annotation {
@deprecated("This returns a LegacyAnnotation, use an explicit Annotation type", "1.1")
- def apply(target: Named, transform: Class[_ <: Transform], value: String) =
+ def apply(target: Named, transform: Class[_ <: Transform], value: String): LegacyAnnotation =
new LegacyAnnotation(target, transform, value)
@deprecated("This uses LegacyAnnotation, use an explicit Annotation type", "1.1")
def unapply(a: LegacyAnnotation): Option[(Named, Class[_ <: Transform], String)] =
@@ -92,13 +121,13 @@ final case class LegacyAnnotation private[firrtl] (
}
def propagate(from: Named, tos: Seq[Named], dup: Named=>Annotation): Seq[Annotation] = tos.map(dup(_))
def check(from: Named, tos: Seq[Named], which: Annotation): Unit = {}
- def duplicate(n: Named) = new LegacyAnnotation(n, transform, value)
+ def duplicate(n: Named): LegacyAnnotation = new LegacyAnnotation(n, transform, value)
}
// Private so that LegacyAnnotation can only be constructed via deprecated Annotation.apply
private[firrtl] object LegacyAnnotation {
// ***** Everything below here is to help people migrate off of old annotations *****
- def errorIllegalAnno(name: String) =
+ def errorIllegalAnno(name: String): Annotation =
throw new Exception(s"Old-style annotations that look like $name are no longer supported")
private val OldDeletedRegex = """(?s)DELETED by ([^\n]*)\n(.*)""".r
@@ -111,7 +140,9 @@ private[firrtl] object LegacyAnnotation {
import firrtl.passes.memlib._
import firrtl.passes.wiring._
import firrtl.passes.clocklist._
+
// Attempt to convert common Annotations and error on the rest of old-style build-in annotations
+ // scalastyle:off
def convertLegacyAnno(anno: LegacyAnnotation): Annotation = anno match {
// All old-style Emitter annotations are illegal
case LegacyAnnotation(_,_,"emitCircuit") => errorIllegalAnno("EmitCircuitAnnotation")
@@ -144,7 +175,8 @@ private[firrtl] object LegacyAnnotation {
case LegacyAnnotation(c: ComponentName, _, SourceRegex(pin)) => SourceAnnotation(c, pin)
case LegacyAnnotation(n, _, SinkRegex(pin)) => SinkAnnotation(n, pin)
case LegacyAnnotation(m: ModuleName, t, text) if t == classOf[BlackBoxSourceHelper] =>
- text.split("\n", 3).toList match {
+ val nArgs = 3
+ text.split("\n", nArgs).toList match {
case "resource" :: id :: _ => BlackBoxResourceAnno(m, id)
case "inline" :: name :: text :: _ => BlackBoxInlineAnno(m, name, text)
case "targetDir" :: targetDir :: _ => BlackBoxTargetDirAnno(targetDir)
@@ -152,11 +184,12 @@ private[firrtl] object LegacyAnnotation {
}
case LegacyAnnotation(_, transform, "noDCE!") if transform == classOf[DeadCodeElimination] =>
NoDCEAnnotation
- case LegacyAnnotation(c: ComponentName, _, "DONTtouch!") => DontTouchAnnotation(c)
+ case LegacyAnnotation(c: ComponentName, _, "DONTtouch!") => DontTouchAnnotation(c.toTarget)
case LegacyAnnotation(c: ModuleName, _, "optimizableExtModule!") =>
OptimizableExtModuleAnnotation(c)
case other => other
}
+ // scalastyle:on
def convertLegacyAnnos(annos: Seq[Annotation]): Seq[Annotation] = {
var warned: Boolean = false
annos.map {