diff options
Diffstat (limited to 'src/main/scala/firrtl/annotations/Annotation.scala')
| -rw-r--r-- | src/main/scala/firrtl/annotations/Annotation.scala | 71 |
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 { |
