aboutsummaryrefslogtreecommitdiff
path: root/src/main/scala/firrtl/annotations
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/scala/firrtl/annotations')
-rw-r--r--src/main/scala/firrtl/annotations/Annotation.scala71
-rw-r--r--src/main/scala/firrtl/annotations/AnnotationUtils.scala18
-rw-r--r--src/main/scala/firrtl/annotations/JsonProtocol.scala30
-rw-r--r--src/main/scala/firrtl/annotations/Named.scala30
-rw-r--r--src/main/scala/firrtl/annotations/Target.scala652
-rw-r--r--src/main/scala/firrtl/annotations/TargetToken.scala46
-rw-r--r--src/main/scala/firrtl/annotations/analysis/DuplicationHelper.scala146
-rw-r--r--src/main/scala/firrtl/annotations/transforms/EliminateTargetPaths.scala167
8 files changed, 51 insertions, 1109 deletions
diff --git a/src/main/scala/firrtl/annotations/Annotation.scala b/src/main/scala/firrtl/annotations/Annotation.scala
index 62c2b335..4b0591bf 100644
--- a/src/main/scala/firrtl/annotations/Annotation.scala
+++ b/src/main/scala/firrtl/annotations/Annotation.scala
@@ -5,15 +5,11 @@ 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 extends Product {
-
+trait Annotation {
/** Update the target based on how signals are renamed */
def update(renames: RenameMap): Seq[Annotation]
@@ -22,29 +18,13 @@ trait Annotation extends Product {
* @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[NoTargetAnnotation] = Seq(this)
+ def update(renames: RenameMap) = Seq(this)
}
/** An Annotation that targets a single [[Named]] thing */
@@ -57,27 +37,18 @@ 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] = {
- 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))
- }
- }
+ 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))
}
@deprecated("Just extend NoTargetAnnotation", "1.1")
@@ -87,7 +58,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): LegacyAnnotation =
+ def apply(target: Named, transform: Class[_ <: Transform], value: String) =
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)] =
@@ -121,13 +92,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): LegacyAnnotation = new LegacyAnnotation(n, transform, value)
+ def duplicate(n: Named) = 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): Annotation =
+ def errorIllegalAnno(name: String) =
throw new Exception(s"Old-style annotations that look like $name are no longer supported")
private val OldDeletedRegex = """(?s)DELETED by ([^\n]*)\n(.*)""".r
@@ -140,9 +111,7 @@ 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")
@@ -175,8 +144,7 @@ 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] =>
- val nArgs = 3
- text.split("\n", nArgs).toList match {
+ text.split("\n", 3).toList match {
case "resource" :: id :: _ => BlackBoxResourceAnno(m, id)
case "inline" :: name :: text :: _ => BlackBoxInlineAnno(m, name, text)
case "targetDir" :: targetDir :: _ => BlackBoxTargetDirAnno(targetDir)
@@ -184,12 +152,11 @@ private[firrtl] object LegacyAnnotation {
}
case LegacyAnnotation(_, transform, "noDCE!") if transform == classOf[DeadCodeElimination] =>
NoDCEAnnotation
- case LegacyAnnotation(c: ComponentName, _, "DONTtouch!") => DontTouchAnnotation(c.toTarget)
+ case LegacyAnnotation(c: ComponentName, _, "DONTtouch!") => DontTouchAnnotation(c)
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 {
diff --git a/src/main/scala/firrtl/annotations/AnnotationUtils.scala b/src/main/scala/firrtl/annotations/AnnotationUtils.scala
index ba9220f7..517cea26 100644
--- a/src/main/scala/firrtl/annotations/AnnotationUtils.scala
+++ b/src/main/scala/firrtl/annotations/AnnotationUtils.scala
@@ -64,29 +64,13 @@ object AnnotationUtils {
case Array(c, m, x) => ComponentName(x, ModuleName(m, CircuitName(c)))
}
- /** Converts a serialized FIRRTL component into a sequence of target tokens
- * @param s
- * @return
- */
- def toSubComponents(s: String): Seq[TargetToken] = {
- import TargetToken._
- def exp2subcomp(e: ir.Expression): Seq[TargetToken] = e match {
- case ir.Reference(name, _) => Seq(Ref(name))
- case ir.SubField(expr, name, _) => exp2subcomp(expr) :+ Field(name)
- case ir.SubIndex(expr, idx, _) => exp2subcomp(expr) :+ Index(idx)
- case ir.SubAccess(expr, idx, _) => Utils.throwInternalError(s"For string $s, cannot convert a subaccess $e into a Target")
- }
- exp2subcomp(toExp(s))
- }
-
-
/** Given a serialized component/subcomponent reference, subindex, subaccess,
* or subfield, return the corresponding IR expression.
* E.g. "foo.bar" becomes SubField(Reference("foo", UnknownType), "bar", UnknownType)
*/
def toExp(s: String): Expression = {
def parse(tokens: Seq[String]): Expression = {
- val DecPattern = """(\d+)""".r
+ val DecPattern = """([1-9]\d*)""".r
def findClose(tokens: Seq[String], index: Int, nOpen: Int): Seq[String] = {
if(index >= tokens.size) {
Utils.error("Cannot find closing bracket ]")
diff --git a/src/main/scala/firrtl/annotations/JsonProtocol.scala b/src/main/scala/firrtl/annotations/JsonProtocol.scala
index 36699151..7b2617f5 100644
--- a/src/main/scala/firrtl/annotations/JsonProtocol.scala
+++ b/src/main/scala/firrtl/annotations/JsonProtocol.scala
@@ -35,39 +35,11 @@ object JsonProtocol {
{ case named: ComponentName => JString(named.serialize) }
))
-
- class TargetSerializer extends CustomSerializer[Target](format => (
- { case JString(s) => Target.deserialize(s) },
- { case named: Target => JString(named.serialize) }
- ))
- class GenericTargetSerializer extends CustomSerializer[GenericTarget](format => (
- { case JString(s) => Target.deserialize(s).asInstanceOf[GenericTarget] },
- { case named: GenericTarget => JString(named.serialize) }
- ))
- class CircuitTargetSerializer extends CustomSerializer[CircuitTarget](format => (
- { case JString(s) => Target.deserialize(s).asInstanceOf[CircuitTarget] },
- { case named: CircuitTarget => JString(named.serialize) }
- ))
- class ModuleTargetSerializer extends CustomSerializer[ModuleTarget](format => (
- { case JString(s) => Target.deserialize(s).asInstanceOf[ModuleTarget] },
- { case named: ModuleTarget => JString(named.serialize) }
- ))
- class InstanceTargetSerializer extends CustomSerializer[InstanceTarget](format => (
- { case JString(s) => Target.deserialize(s).asInstanceOf[InstanceTarget] },
- { case named: InstanceTarget => JString(named.serialize) }
- ))
- class ReferenceTargetSerializer extends CustomSerializer[ReferenceTarget](format => (
- { case JString(s) => Target.deserialize(s).asInstanceOf[ReferenceTarget] },
- { case named: ReferenceTarget => JString(named.serialize) }
- ))
-
/** Construct Json formatter for annotations */
def jsonFormat(tags: Seq[Class[_ <: Annotation]]) = {
Serialization.formats(FullTypeHints(tags.toList)).withTypeHintFieldName("class") +
new TransformClassSerializer + new NamedSerializer + new CircuitNameSerializer +
- new ModuleNameSerializer + new ComponentNameSerializer + new TargetSerializer +
- new GenericTargetSerializer + new CircuitTargetSerializer + new ModuleTargetSerializer +
- new InstanceTargetSerializer + new ReferenceTargetSerializer
+ new ModuleNameSerializer + new ComponentNameSerializer
}
/** Serialize annotations to a String for emission */
diff --git a/src/main/scala/firrtl/annotations/Named.scala b/src/main/scala/firrtl/annotations/Named.scala
new file mode 100644
index 00000000..3da75884
--- /dev/null
+++ b/src/main/scala/firrtl/annotations/Named.scala
@@ -0,0 +1,30 @@
+// See LICENSE for license details.
+
+package firrtl
+package annotations
+
+import firrtl.ir.Expression
+import AnnotationUtils.{validModuleName, validComponentName, toExp}
+
+/**
+ * Named classes associate an annotation with a component in a Firrtl circuit
+ */
+sealed trait Named {
+ def serialize: String
+}
+
+final case class CircuitName(name: String) extends Named {
+ if(!validModuleName(name)) throw AnnotationException(s"Illegal circuit name: $name")
+ def serialize: String = name
+}
+
+final case class ModuleName(name: String, circuit: CircuitName) extends Named {
+ if(!validModuleName(name)) throw AnnotationException(s"Illegal module name: $name")
+ def serialize: String = circuit.serialize + "." + name
+}
+
+final case class ComponentName(name: String, module: ModuleName) extends Named {
+ if(!validComponentName(name)) throw AnnotationException(s"Illegal component name: $name")
+ def expr: Expression = toExp(name)
+ def serialize: String = module.serialize + "." + name
+}
diff --git a/src/main/scala/firrtl/annotations/Target.scala b/src/main/scala/firrtl/annotations/Target.scala
deleted file mode 100644
index dcf5cb02..00000000
--- a/src/main/scala/firrtl/annotations/Target.scala
+++ /dev/null
@@ -1,652 +0,0 @@
-// See LICENSE for license details.
-
-package firrtl
-package annotations
-
-import firrtl.ir.Expression
-import AnnotationUtils.{toExp, validComponentName, validModuleName}
-import TargetToken._
-
-import scala.collection.mutable
-
-/** Refers to something in a FIRRTL [[firrtl.ir.Circuit]]. Used for Annotation targets.
- *
- * Can be in various states of completion/resolved:
- * - Legal: [[TargetToken]]'s in tokens are in an order that makes sense
- * - Complete: circuitOpt and moduleOpt are non-empty, and all Instance(_) are followed by OfModule(_)
- * - Local: tokens does not refer to things through an instance hierarchy (no Instance(_) or OfModule(_) tokens)
- */
-sealed trait Target extends Named {
-
- /** @return Circuit name, if it exists */
- def circuitOpt: Option[String]
-
- /** @return Module name, if it exists */
- def moduleOpt: Option[String]
-
- /** @return [[Target]] tokens */
- def tokens: Seq[TargetToken]
-
- /** @return Returns a new [[GenericTarget]] with new values */
- def modify(circuitOpt: Option[String] = circuitOpt,
- moduleOpt: Option[String] = moduleOpt,
- tokens: Seq[TargetToken] = tokens): GenericTarget = GenericTarget(circuitOpt, moduleOpt, tokens.toVector)
-
- /** @return Human-readable serialization */
- def serialize: String = {
- val circuitString = "~" + circuitOpt.getOrElse("???")
- val moduleString = "|" + moduleOpt.getOrElse("???")
- val tokensString = tokens.map {
- case Ref(r) => s">$r"
- case Instance(i) => s"/$i"
- case OfModule(o) => s":$o"
- case Field(f) => s".$f"
- case Index(v) => s"[$v]"
- case Clock => s"@clock"
- case Reset => s"@reset"
- case Init => s"@init"
- }.mkString("")
- if(moduleOpt.isEmpty && tokens.isEmpty) {
- circuitString
- } else if(tokens.isEmpty) {
- circuitString + moduleString
- } else {
- circuitString + moduleString + tokensString
- }
- }
-
- /** @return Converts this [[Target]] into a [[GenericTarget]] */
- def toGenericTarget: GenericTarget = GenericTarget(circuitOpt, moduleOpt, tokens.toVector)
-
- /** @return Converts this [[Target]] into either a [[CircuitName]], [[ModuleName]], or [[ComponentName]] */
- @deprecated("Use Target instead, will be removed in 1.3", "1.2")
- def toNamed: Named = toGenericTarget.toNamed
-
- /** @return If legal, convert this [[Target]] into a [[CompleteTarget]] */
- def getComplete: Option[CompleteTarget]
-
- /** @return Converts this [[Target]] into a [[CompleteTarget]] */
- def complete: CompleteTarget = getComplete.get
-
- /** @return Converts this [[Target]] into a [[CompleteTarget]], or if it can't, return original [[Target]] */
- def tryToComplete: Target = getComplete.getOrElse(this)
-
- /** Whether the target is directly instantiated in its root module */
- def isLocal: Boolean
-}
-
-object Target {
-
- def apply(circuitOpt: Option[String], moduleOpt: Option[String], reference: Seq[TargetToken]): GenericTarget =
- GenericTarget(circuitOpt, moduleOpt, reference.toVector)
-
- def unapply(t: Target): Option[(Option[String], Option[String], Seq[TargetToken])] =
- Some((t.circuitOpt, t.moduleOpt, t.tokens))
-
- case class NamedException(message: String) extends Exception(message)
-
- implicit def convertCircuitTarget2CircuitName(c: CircuitTarget): CircuitName = c.toNamed
- implicit def convertModuleTarget2ModuleName(c: ModuleTarget): ModuleName = c.toNamed
- implicit def convertIsComponent2ComponentName(c: IsComponent): ComponentName = c.toNamed
- implicit def convertTarget2Named(c: Target): Named = c.toNamed
- implicit def convertCircuitName2CircuitTarget(c: CircuitName): CircuitTarget = c.toTarget
- implicit def convertModuleName2ModuleTarget(c: ModuleName): ModuleTarget = c.toTarget
- implicit def convertComponentName2ReferenceTarget(c: ComponentName): ReferenceTarget = c.toTarget
- implicit def convertNamed2Target(n: Named): CompleteTarget = n.toTarget
-
- /** Converts [[ComponentName]]'s name into TargetTokens
- * @param name
- * @return
- */
- def toTargetTokens(name: String): Seq[TargetToken] = {
- val tokens = AnnotationUtils.tokenize(name)
- val subComps = mutable.ArrayBuffer[TargetToken]()
- subComps += Ref(tokens.head)
- if(tokens.tail.nonEmpty) {
- tokens.tail.zip(tokens.tail.tail).foreach {
- case (".", value: String) => subComps += Field(value)
- case ("[", value: String) => subComps += Index(value.toInt)
- case other =>
- }
- }
- subComps
- }
-
- /** Checks if seq only contains [[TargetToken]]'s with select keywords
- * @param seq
- * @param keywords
- * @return
- */
- def isOnly(seq: Seq[TargetToken], keywords:String*): Boolean = {
- seq.map(_.is(keywords:_*)).foldLeft(false)(_ || _) && keywords.nonEmpty
- }
-
- /** @return [[Target]] from human-readable serialization */
- def deserialize(s: String): Target = {
- val regex = """(?=[~|>/:.\[@])"""
- s.split(regex).foldLeft(GenericTarget(None, None, Vector.empty)) { (t, tokenString) =>
- val value = tokenString.tail
- tokenString(0) match {
- case '~' if t.circuitOpt.isEmpty && t.moduleOpt.isEmpty && t.tokens.isEmpty =>
- if(value == "???") t else t.copy(circuitOpt = Some(value))
- case '|' if t.moduleOpt.isEmpty && t.tokens.isEmpty =>
- if(value == "???") t else t.copy(moduleOpt = Some(value))
- case '/' => t.add(Instance(value))
- case ':' => t.add(OfModule(value))
- case '>' => t.add(Ref(value))
- case '.' => t.add(Field(value))
- case '[' if value.dropRight(1).toInt >= 0 => t.add(Index(value.dropRight(1).toInt))
- case '@' if value == "clock" => t.add(Clock)
- case '@' if value == "init" => t.add(Init)
- case '@' if value == "reset" => t.add(Reset)
- case other => throw NamedException(s"Cannot deserialize Target: $s")
- }
- }.tryToComplete
- }
-}
-
-/** Represents incomplete or non-standard [[Target]]s
- * @param circuitOpt Optional circuit name
- * @param moduleOpt Optional module name
- * @param tokens [[TargetToken]]s to represent the target in a circuit and module
- */
-case class GenericTarget(circuitOpt: Option[String],
- moduleOpt: Option[String],
- tokens: Vector[TargetToken]) extends Target {
-
- override def toGenericTarget: GenericTarget = this
-
- override def toNamed: Named = getComplete match {
- case Some(c: IsComponent) if c.isLocal => c.toNamed
- case Some(c: ModuleTarget) => c.toNamed
- case Some(c: CircuitTarget) => c.toNamed
- case other => throw Target.NamedException(s"Cannot convert $this to [[Named]]")
- }
-
- override def toTarget: CompleteTarget = getComplete.get
-
- override def getComplete: Option[CompleteTarget] = {
- if(!isComplete) None else {
- val target = this match {
- case GenericTarget(Some(c), None, Vector()) => CircuitTarget(c)
- case GenericTarget(Some(c), Some(m), Vector()) => ModuleTarget(c, m)
- case GenericTarget(Some(c), Some(m), Ref(r) +: component) => ReferenceTarget(c, m, Nil, r, component)
- case GenericTarget(Some(c), Some(m), Instance(i) +: OfModule(o) +: Vector()) => InstanceTarget(c, m, Nil, i, o)
- case GenericTarget(Some(c), Some(m), component) =>
- val path = getPath.getOrElse(Nil)
- (getRef, getInstanceOf) match {
- case (Some((r, comps)), _) => ReferenceTarget(c, m, path, r, comps)
- case (None, Some((i, o))) => InstanceTarget(c, m, path, i, o)
- }
- }
- Some(target)
- }
- }
-
- override def isLocal: Boolean = !(getPath.nonEmpty && getPath.get.nonEmpty)
-
- /** If complete, return this [[GenericTarget]]'s path
- * @return
- */
- def getPath: Option[Seq[(Instance, OfModule)]] = if(isComplete) {
- val allInstOfs = tokens.grouped(2).collect { case Seq(i: Instance, o:OfModule) => (i, o)}.toSeq
- if(tokens.nonEmpty && tokens.last.isInstanceOf[OfModule]) Some(allInstOfs.dropRight(1)) else Some(allInstOfs)
- } else {
- None
- }
-
- /** If complete and a reference, return the reference and subcomponents
- * @return
- */
- def getRef: Option[(String, Seq[TargetToken])] = if(isComplete) {
- val (optRef, comps) = tokens.foldLeft((None: Option[String], Vector.empty[TargetToken])) {
- case ((None, v), Ref(r)) => (Some(r), v)
- case ((r: Some[String], comps), c) => (r, comps :+ c)
- case ((r, v), other) => (None, v)
- }
- optRef.map(x => (x, comps))
- } else {
- None
- }
-
- /** If complete and an instance target, return the instance and ofmodule
- * @return
- */
- def getInstanceOf: Option[(String, String)] = if(isComplete) {
- tokens.grouped(2).foldLeft(None: Option[(String, String)]) {
- case (instOf, Seq(i: Instance, o: OfModule)) => Some((i.value, o.value))
- case (instOf, _) => None
- }
- } else {
- None
- }
-
- /** Requires the last [[TargetToken]] in tokens to be one of the [[TargetToken]] keywords
- * @param default Return value if tokens is empty
- * @param keywords
- */
- private def requireLast(default: Boolean, keywords: String*): Unit = {
- val isOne = if (tokens.isEmpty) default else tokens.last.is(keywords: _*)
- require(isOne, s"${tokens.last} is not one of $keywords")
- }
-
- /** Appends a target token to tokens, asserts legality
- * @param token
- * @return
- */
- def add(token: TargetToken): GenericTarget = {
- token match {
- case _: Instance => requireLast(true, "inst", "of")
- case _: OfModule => requireLast(false, "inst")
- case _: Ref => requireLast(true, "inst", "of")
- case _: Field => requireLast(true, "ref", "[]", ".", "init", "clock", "reset")
- case _: Index => requireLast(true, "ref", "[]", ".", "init", "clock", "reset")
- case Init => requireLast(true, "ref", "[]", ".", "init", "clock", "reset")
- case Clock => requireLast(true, "ref", "[]", ".", "init", "clock", "reset")
- case Reset => requireLast(true, "ref", "[]", ".", "init", "clock", "reset")
- }
- this.copy(tokens = tokens :+ token)
- }
-
- /** Removes n number of target tokens from the right side of [[tokens]] */
- def remove(n: Int): GenericTarget = this.copy(tokens = tokens.dropRight(n))
-
- /** Optionally tries to append token to tokens, fails return is not a legal Target */
- def optAdd(token: TargetToken): Option[Target] = {
- try{
- Some(add(token))
- } catch {
- case _: IllegalArgumentException => None
- }
- }
-
- /** Checks whether the component is legal (incomplete is ok)
- * @return
- */
- def isLegal: Boolean = {
- try {
- var comp: GenericTarget = this.copy(tokens = Vector.empty)
- for(token <- tokens) {
- comp = comp.add(token)
- }
- true
- } catch {
- case _: IllegalArgumentException => false
- }
- }
-
- /** Checks whether the component is legal and complete, meaning the circuitOpt and moduleOpt are nonEmpty and
- * all Instance(_) are followed by OfModule(_)
- * @return
- */
- def isComplete: Boolean = {
- isLegal && (isCircuitTarget || isModuleTarget || (isComponentTarget && tokens.tails.forall {
- case Instance(_) +: OfModule(_) +: tail => true
- case Instance(_) +: x +: tail => false
- case x +: OfModule(_) +: tail => false
- case _ => true
- } ))
- }
-
-
- def isCircuitTarget: Boolean = circuitOpt.nonEmpty && moduleOpt.isEmpty && tokens.isEmpty
- def isModuleTarget: Boolean = circuitOpt.nonEmpty && moduleOpt.nonEmpty && tokens.isEmpty
- def isComponentTarget: Boolean = circuitOpt.nonEmpty && moduleOpt.nonEmpty && tokens.nonEmpty
-}
-
-/** Concretely points to a FIRRTL target, no generic selectors
- * IsLegal
- */
-trait CompleteTarget extends Target {
-
- /** @return The circuit of this target */
- def circuit: String
-
- /** @return The [[CircuitTarget]] of this target's circuit */
- def circuitTarget: CircuitTarget = CircuitTarget(circuitOpt.get)
-
- def getComplete: Option[CompleteTarget] = Some(this)
-
- /** Adds another level of instance hierarchy
- * Example: Given root=A and instance=b, transforms (Top, B)/c:C -> (Top, A)/b:B/c:C
- * @param root
- * @param instance
- * @return
- */
- def addHierarchy(root: String, instance: String): IsComponent
-
- override def toTarget: CompleteTarget = this
-}
-
-
-/** A member of a FIRRTL Circuit (e.g. cannot point to a CircuitTarget)
- * Concrete Subclasses are: [[ModuleTarget]], [[InstanceTarget]], and [[ReferenceTarget]]
- */
-trait IsMember extends CompleteTarget {
-
- /** @return Root module, e.g. top-level module of this target */
- def module: String
-
- /** @return Returns the instance hierarchy path, if one exists */
- def path: Seq[(Instance, OfModule)]
-
- /** @return Creates a path, assuming all Instance and OfModules in this [[IsMember]] is used as a path */
- def asPath: Seq[(Instance, OfModule)]
-
- /** @return Tokens of just this member's path */
- def justPath: Seq[TargetToken]
-
- /** @return Local tokens of what this member points (not a path) */
- def notPath: Seq[TargetToken]
-
- /** @return Same target without a path */
- def pathlessTarget: IsMember
-
- /** @return Member's path target */
- def pathTarget: CompleteTarget
-
- /** @return Member's top-level module target */
- def moduleTarget: ModuleTarget = ModuleTarget(circuitOpt.get, moduleOpt.get)
-
- /** @return Member's parent target */
- def targetParent: CompleteTarget
-
- /** @return List of local Instance Targets refering to each instance/ofModule in this member's path */
- def pathAsTargets: Seq[InstanceTarget] = {
- val targets = mutable.ArrayBuffer[InstanceTarget]()
- path.foldLeft((module, Vector.empty[InstanceTarget])) {
- case ((m, vec), (Instance(i), OfModule(o))) =>
- (o, vec :+ InstanceTarget(circuit, m, Nil, i, o))
- }._2
- }
-
- /** Resets this target to have a new path
- * @param newPath
- * @return
- */
- def setPathTarget(newPath: IsModule): CompleteTarget
-}
-
-/** References a module-like target (e.g. a [[ModuleTarget]] or an [[InstanceTarget]])
- */
-trait IsModule extends IsMember {
-
- /** @return Creates a new Target, appending a ref */
- def ref(value: String): ReferenceTarget
-
- /** @return Creates a new Target, appending an instance and ofmodule */
- def instOf(instance: String, of: String): InstanceTarget
-}
-
-/** A component of a FIRRTL Module (e.g. cannot point to a CircuitTarget or ModuleTarget)
- */
-trait IsComponent extends IsMember {
-
- /** @return The [[ModuleTarget]] of the module that directly contains this component */
- def encapsulatingModule: String = if(path.isEmpty) module else path.last._2.value
-
- /** Removes n levels of instance hierarchy
- *
- * Example: n=1, transforms (Top, A)/b:B/c:C -> (Top, B)/c:C
- * @param n
- * @return
- */
- def stripHierarchy(n: Int): IsMember
-
- override def toNamed: ComponentName = {
- if(isLocal){
- val mn = ModuleName(module, CircuitName(circuit))
- Seq(tokens:_*) match {
- case Seq(Ref(name)) => ComponentName(name, mn)
- case Ref(_) :: tail if Target.isOnly(tail, ".", "[]") =>
- val name = tokens.foldLeft(""){
- case ("", Ref(name)) => name
- case (string, Field(value)) => s"$string.$value"
- case (string, Index(value)) => s"$string[$value]"
- }
- ComponentName(name, mn)
- case Seq(Instance(name), OfModule(o)) => ComponentName(name, mn)
- }
- } else {
- throw new Exception(s"Cannot convert $this to [[ComponentName]]")
- }
- }
-
- override def justPath: Seq[TargetToken] = path.foldLeft(Vector.empty[TargetToken]) {
- case (vec, (i, o)) => vec ++ Seq(i, o)
- }
-
- override def pathTarget: IsModule = {
- if(path.isEmpty) moduleTarget else {
- val (i, o) = path.last
- InstanceTarget(circuit, module, path.dropRight(1), i.value, o.value)
- }
- }
-
- override def tokens = justPath ++ notPath
-
- override def isLocal = path.isEmpty
-}
-
-
-/** Target pointing to a FIRRTL [[firrtl.ir.Circuit]]
- * @param circuit Name of a FIRRTL circuit
- */
-case class CircuitTarget(circuit: String) extends CompleteTarget {
-
- /** Creates a [[ModuleTarget]] of provided name and this circuit
- * @param m
- * @return
- */
- def module(m: String): ModuleTarget = ModuleTarget(circuit, m)
-
- override def circuitOpt: Option[String] = Some(circuit)
-
- override def moduleOpt: Option[String] = None
-
- override def tokens = Nil
-
- override def isLocal = true
-
- override def addHierarchy(root: String, instance: String): ReferenceTarget =
- ReferenceTarget(circuit, root, Nil, instance, Nil)
-
- override def toNamed: CircuitName = CircuitName(circuit)
-}
-
-/** Target pointing to a FIRRTL [[firrtl.ir.DefModule]]
- * @param circuit Circuit containing the module
- * @param module Name of the module
- */
-case class ModuleTarget(circuit: String, module: String) extends IsModule {
-
- override def circuitOpt: Option[String] = Some(circuit)
-
- override def moduleOpt: Option[String] = Some(module)
-
- override def tokens: Seq[TargetToken] = Nil
-
- override def targetParent: CircuitTarget = CircuitTarget(circuit)
-
- override def addHierarchy(root: String, instance: String): InstanceTarget = InstanceTarget(circuit, root, Nil, instance, module)
-
- override def ref(value: String): ReferenceTarget = ReferenceTarget(circuit, module, Nil, value, Nil)
-
- override def instOf(instance: String, of: String): InstanceTarget = InstanceTarget(circuit, module, Nil, instance, of)
-
- override def asPath = Nil
-
- override def path: Seq[(Instance, OfModule)] = Nil
-
- override def justPath: Seq[TargetToken] = Nil
-
- override def notPath: Seq[TargetToken] = Nil
-
- override def pathlessTarget: ModuleTarget = this
-
- override def pathTarget: ModuleTarget = this
-
- override def isLocal = true
-
- override def setPathTarget(newPath: IsModule): IsModule = newPath
-
- override def toNamed: ModuleName = ModuleName(module, CircuitName(circuit))
-}
-
-/** Target pointing to a declared named component in a [[firrtl.ir.DefModule]]
- * This includes: [[firrtl.ir.Port]], [[firrtl.ir.DefWire]], [[firrtl.ir.DefRegister]], [[firrtl.ir.DefInstance]],
- * [[firrtl.ir.DefMemory]], [[firrtl.ir.DefNode]]
- * @param circuit Name of the encapsulating circuit
- * @param module Name of the root module of this reference
- * @param path Path through instance/ofModules
- * @param ref Name of component
- * @param component Subcomponent of this reference, e.g. field or index
- */
-case class ReferenceTarget(circuit: String,
- module: String,
- override val path: Seq[(Instance, OfModule)],
- ref: String,
- component: Seq[TargetToken]) extends IsComponent {
-
- /** @param value Index value of this target
- * @return A new [[ReferenceTarget]] to the specified index of this [[ReferenceTarget]]
- */
- def index(value: Int): ReferenceTarget = ReferenceTarget(circuit, module, path, ref, component :+ Index(value))
-
- /** @param value Field name of this target
- * @return A new [[ReferenceTarget]] to the specified field of this [[ReferenceTarget]]
- */
- def field(value: String): ReferenceTarget = ReferenceTarget(circuit, module, path, ref, component :+ Field(value))
-
- /** @return The initialization value of this reference, must be to a [[firrtl.ir.DefRegister]] */
- def init: ReferenceTarget = ReferenceTarget(circuit, module, path, ref, component :+ Init)
-
- /** @return The reset signal of this reference, must be to a [[firrtl.ir.DefRegister]] */
- def reset: ReferenceTarget = ReferenceTarget(circuit, module, path, ref, component :+ Reset)
-
- /** @return The clock signal of this reference, must be to a [[firrtl.ir.DefRegister]] */
- def clock: ReferenceTarget = ReferenceTarget(circuit, module, path, ref, component :+ Clock)
-
- override def circuitOpt: Option[String] = Some(circuit)
-
- override def moduleOpt: Option[String] = Some(module)
-
- override def targetParent: CompleteTarget = component match {
- case Nil =>
- if(path.isEmpty) moduleTarget else {
- val (i, o) = path.last
- InstanceTarget(circuit, module, path.dropRight(1), i.value, o.value)
- }
- case other => ReferenceTarget(circuit, module, path, ref, component.dropRight(1))
- }
-
- override def notPath: Seq[TargetToken] = Ref(ref) +: component
-
- override def addHierarchy(root: String, instance: String): ReferenceTarget =
- ReferenceTarget(circuit, root, (Instance(instance), OfModule(module)) +: path, ref, component)
-
- override def stripHierarchy(n: Int): ReferenceTarget = {
- require(path.size >= n, s"Cannot strip $n levels of hierarchy from $this")
- if(n == 0) this else {
- val newModule = path(n - 1)._2.value
- ReferenceTarget(circuit, newModule, path.drop(n), ref, component)
- }
- }
-
- override def pathlessTarget: ReferenceTarget = ReferenceTarget(circuit, encapsulatingModule, Nil, ref, component)
-
- override def setPathTarget(newPath: IsModule): ReferenceTarget =
- ReferenceTarget(newPath.circuit, newPath.module, newPath.asPath, ref, component)
-
- override def asPath: Seq[(Instance, OfModule)] = path
-}
-
-/** Points to an instance declaration of a module (termed an ofModule)
- * @param circuit Encapsulating circuit
- * @param module Root module (e.g. the base module of this target)
- * @param path Path through instance/ofModules
- * @param instance Name of the instance
- * @param ofModule Name of the instance's module
- */
-case class InstanceTarget(circuit: String,
- module: String,
- override val path: Seq[(Instance, OfModule)],
- instance: String,
- ofModule: String) extends IsModule with IsComponent {
-
- /** @return a [[ReferenceTarget]] referring to this declaration of this instance */
- def asReference: ReferenceTarget = ReferenceTarget(circuit, module, path, instance, Nil)
-
- /** @return a [[ReferenceTarget]] referring to declaration of this ofModule */
- def ofModuleTarget: ModuleTarget = ModuleTarget(circuit, ofModule)
-
- override def circuitOpt: Option[String] = Some(circuit)
-
- override def moduleOpt: Option[String] = Some(module)
-
- override def targetParent: IsModule = {
- if(isLocal) ModuleTarget(circuit, module) else {
- val (newInstance, newOfModule) = path.last
- InstanceTarget(circuit, module, path.dropRight(1), newInstance.value, newOfModule.value)
- }
- }
-
- override def addHierarchy(root: String, inst: String): InstanceTarget =
- InstanceTarget(circuit, root, (Instance(inst), OfModule(module)) +: path, instance, ofModule)
-
- override def ref(value: String): ReferenceTarget = ReferenceTarget(circuit, module, asPath, value, Nil)
-
- override def instOf(inst: String, of: String): InstanceTarget = InstanceTarget(circuit, module, asPath, inst, of)
-
- override def stripHierarchy(n: Int): IsModule = {
- require(path.size >= n, s"Cannot strip $n levels of hierarchy from $this")
- if(n == 0) this else {
- val newModule = path(n - 1)._2.value
- InstanceTarget(circuit, newModule, path.drop(n), instance, ofModule)
- }
- }
-
- override def asPath: Seq[(Instance, OfModule)] = path :+ (Instance(instance), OfModule(ofModule))
-
- override def pathlessTarget: InstanceTarget = InstanceTarget(circuit, encapsulatingModule, Nil, instance, ofModule)
-
- override def notPath = Seq(Instance(instance), OfModule(ofModule))
-
- override def setPathTarget(newPath: IsModule): InstanceTarget =
- InstanceTarget(newPath.circuit, newPath.module, newPath.asPath, instance, ofModule)
-}
-
-
-/** Named classes associate an annotation with a component in a Firrtl circuit */
-@deprecated("Use Target instead, will be removed in 1.3", "1.2")
-sealed trait Named {
- def serialize: String
- def toTarget: CompleteTarget
-}
-
-@deprecated("Use Target instead, will be removed in 1.3", "1.2")
-final case class CircuitName(name: String) extends Named {
- if(!validModuleName(name)) throw AnnotationException(s"Illegal circuit name: $name")
- def serialize: String = name
- def toTarget: CircuitTarget = CircuitTarget(name)
-}
-
-@deprecated("Use Target instead, will be removed in 1.3", "1.2")
-final case class ModuleName(name: String, circuit: CircuitName) extends Named {
- if(!validModuleName(name)) throw AnnotationException(s"Illegal module name: $name")
- def serialize: String = circuit.serialize + "." + name
- def toTarget: ModuleTarget = ModuleTarget(circuit.name, name)
-}
-
-@deprecated("Use Target instead, will be removed in 1.3", "1.2")
-final case class ComponentName(name: String, module: ModuleName) extends Named {
- if(!validComponentName(name)) throw AnnotationException(s"Illegal component name: $name")
- def expr: Expression = toExp(name)
- def serialize: String = module.serialize + "." + name
- def toTarget: ReferenceTarget = {
- Target.toTargetTokens(name).toList match {
- case Ref(r) :: components => ReferenceTarget(module.circuit.name, module.name, Nil, r, components)
- case other => throw Target.NamedException(s"Cannot convert $this into [[ReferenceTarget]]: $other")
- }
- }
-}
diff --git a/src/main/scala/firrtl/annotations/TargetToken.scala b/src/main/scala/firrtl/annotations/TargetToken.scala
deleted file mode 100644
index 587f30eb..00000000
--- a/src/main/scala/firrtl/annotations/TargetToken.scala
+++ /dev/null
@@ -1,46 +0,0 @@
-// See LICENSE for license details.
-
-package firrtl.annotations
-
-/** Building block to represent a [[Target]] of a FIRRTL component */
-sealed trait TargetToken {
- def keyword: String
- def value: Any
-
- /** Returns whether this token is one of the type of tokens whose keyword is passed as an argument
- * @param keywords
- * @return
- */
- def is(keywords: String*): Boolean = {
- keywords.map { kw =>
- require(TargetToken.keyword2targettoken.keySet.contains(kw),
- s"Keyword $kw must be in set ${TargetToken.keyword2targettoken.keys}")
- val lastClass = this.getClass
- lastClass == TargetToken.keyword2targettoken(kw)("0").getClass
- }.reduce(_ || _)
- }
-}
-
-/** Object containing all [[TargetToken]] subclasses */
-case object TargetToken {
- case class Instance(value: String) extends TargetToken { override def keyword: String = "inst" }
- case class OfModule(value: String) extends TargetToken { override def keyword: String = "of" }
- case class Ref(value: String) extends TargetToken { override def keyword: String = "ref" }
- case class Index(value: Int) extends TargetToken { override def keyword: String = "[]" }
- case class Field(value: String) extends TargetToken { override def keyword: String = "." }
- case object Clock extends TargetToken { override def keyword: String = "clock"; val value = "" }
- case object Init extends TargetToken { override def keyword: String = "init"; val value = "" }
- case object Reset extends TargetToken { override def keyword: String = "reset"; val value = "" }
-
- val keyword2targettoken = Map(
- "inst" -> ((value: String) => Instance(value)),
- "of" -> ((value: String) => OfModule(value)),
- "ref" -> ((value: String) => Ref(value)),
- "[]" -> ((value: String) => Index(value.toInt)),
- "." -> ((value: String) => Field(value)),
- "clock" -> ((value: String) => Clock),
- "init" -> ((value: String) => Init),
- "reset" -> ((value: String) => Reset)
- )
-}
-
diff --git a/src/main/scala/firrtl/annotations/analysis/DuplicationHelper.scala b/src/main/scala/firrtl/annotations/analysis/DuplicationHelper.scala
deleted file mode 100644
index ba3ca9a9..00000000
--- a/src/main/scala/firrtl/annotations/analysis/DuplicationHelper.scala
+++ /dev/null
@@ -1,146 +0,0 @@
-// See LICENSE for license details.
-
-package firrtl.annotations.analysis
-
-import firrtl.Namespace
-import firrtl.annotations._
-import firrtl.annotations.TargetToken.{Instance, OfModule, Ref}
-import firrtl.Utils.throwInternalError
-
-import scala.collection.mutable
-
-/** Used by [[firrtl.annotations.transforms.EliminateTargetPaths]] to eliminate target paths
- * Calculates needed modifications to a circuit's module/instance hierarchy
- */
-case class DuplicationHelper(existingModules: Set[String]) {
- // Maps instances to the module it instantiates (an ofModule)
- type InstanceOfModuleMap = mutable.HashMap[Instance, OfModule]
-
- // Maps a module to the instance/ofModules it instantiates
- type ModuleHasInstanceOfModuleMap = mutable.HashMap[String, InstanceOfModuleMap]
-
- // Maps original module names to new duplicated modules and their encapsulated instance/ofModules
- type DupMap = mutable.HashMap[String, ModuleHasInstanceOfModuleMap]
-
- // Internal state to keep track of how paths duplicate
- private val dupMap = new DupMap()
-
- // Internal record of which paths are renamed to which new names, in the case of a collision
- private val cachedNames = mutable.HashMap[(String, Seq[(Instance, OfModule)]), String]() ++
- existingModules.map(m => (m, Nil) -> m)
-
- // Internal record of all paths to ensure unique name generation
- private val allModules = mutable.HashSet[String]() ++ existingModules
-
- /** Updates internal state (dupMap) to calculate instance hierarchy modifications so t's tokens in an instance can be
- * expressed as a tokens in a module (e.g. uniquify/duplicate the instance path in t's tokens)
- * @param t An instance-resolved component
- */
- def expandHierarchy(t: IsMember): Unit = {
- val path = t.asPath
- path.reverse.tails.map { _.reverse }.foreach { duplicate(t.module, _) }
- }
-
- /** Updates dupMap with how original module names map to new duplicated module names
- * @param top Root module of a component
- * @param path Path down instance hierarchy of a component
- */
- private def duplicate(top: String, path: Seq[(Instance, OfModule)]): Unit = {
- val (originalModule, instance, ofModule) = path.size match {
- case 0 => return
- case 1 => (top, path.head._1, path.head._2)
- case _ => (path(path.length - 2)._2.value, path.last._1, path.last._2)
- }
- val originalModuleToDupedModule = dupMap.getOrElseUpdate(originalModule, new ModuleHasInstanceOfModuleMap())
- val dupedModule = getModuleName(top, path.dropRight(1))
- val dupedModuleToInstances = originalModuleToDupedModule.getOrElseUpdate(dupedModule, new InstanceOfModuleMap())
- val dupedInstanceModule = getModuleName(top, path)
- dupedModuleToInstances += ((instance, OfModule(dupedInstanceModule)))
-
- val originalInstanceModuleToDupedModule = dupMap.getOrElseUpdate(ofModule.value, new ModuleHasInstanceOfModuleMap())
- originalInstanceModuleToDupedModule.getOrElseUpdate(dupedInstanceModule, new InstanceOfModuleMap())
- }
-
- /** Deterministic name-creation of a duplicated module
- * @param top
- * @param path
- * @return
- */
- def getModuleName(top: String, path: Seq[(Instance, OfModule)]): String = {
- cachedNames.get((top, path)) match {
- case None => // Need a new name
- val prefix = path.last._2.value + "___"
- val postfix = top + "_" + path.map { case (i, m) => i.value }.mkString("_")
- val ns = mutable.HashSet(allModules.toSeq: _*)
- val finalName = firrtl.passes.Uniquify.findValidPrefix(prefix, Seq(postfix), ns) + postfix
- allModules += finalName
- cachedNames((top, path)) = finalName
- finalName
- case Some(newName) => newName
- }
- }
-
- /** Return the duplicated module (formerly originalOfModule) instantiated by instance in newModule (formerly
- * originalModule)
- * @param originalModule original encapsulating module
- * @param newModule new name of encapsulating module
- * @param instance instance name being declared in encapsulating module
- * @param originalOfModule original module being instantiated in originalModule
- * @return
- */
- def getNewOfModule(originalModule: String,
- newModule: String,
- instance: Instance,
- originalOfModule: OfModule): OfModule = {
- dupMap.get(originalModule) match {
- case None => // No duplication, can return originalOfModule
- originalOfModule
- case Some(newDupedModules) =>
- newDupedModules.get(newModule) match {
- case None if newModule != originalModule => throwInternalError("BAD")
- case None => // No duplication, can return originalOfModule
- originalOfModule
- case Some(newDupedModule) =>
- newDupedModule.get(instance) match {
- case None => // Not duped, can return originalOfModule
- originalOfModule
- case Some(newOfModule) =>
- newOfModule
- }
- }
- }
- }
-
- /** Returns the names of this module's duplicated (including the original name)
- * @param module
- * @return
- */
- def getDuplicates(module: String): Set[String] = {
- dupMap.get(module).map(_.keys.toSet[String]).getOrElse(Set.empty[String]) ++ Set(module)
- }
-
- /** Rewrites t with new module/instance hierarchy calculated after repeated calls to [[expandHierarchy]]
- * @param t A target
- * @return t rewritten, is a seq because if the t.module has been duplicated, it must now refer to multiple modules
- */
- def makePathless(t: IsMember): Seq[IsMember] = {
- val top = t.module
- val path = t.asPath
- val newTops = getDuplicates(top)
- newTops.map { newTop =>
- val newPath = mutable.ArrayBuffer[TargetToken]()
- path.foldLeft((top, newTop)) { case ((originalModule, newModule), (instance, ofModule)) =>
- val newOfModule = getNewOfModule(originalModule, newModule, instance, ofModule)
- newPath ++= Seq(instance, newOfModule)
- (ofModule.value, newOfModule.value)
- }
- val module = if(newPath.nonEmpty) newPath.last.value.toString else newTop
- t.notPath match {
- case Seq() => ModuleTarget(t.circuit, module)
- case Instance(i) +: OfModule(m) +: Seq() => ModuleTarget(t.circuit, module)
- case Ref(r) +: components => ReferenceTarget(t.circuit, module, Nil, r, components)
- }
- }.toSeq
- }
-}
-
diff --git a/src/main/scala/firrtl/annotations/transforms/EliminateTargetPaths.scala b/src/main/scala/firrtl/annotations/transforms/EliminateTargetPaths.scala
deleted file mode 100644
index 8f604c9f..00000000
--- a/src/main/scala/firrtl/annotations/transforms/EliminateTargetPaths.scala
+++ /dev/null
@@ -1,167 +0,0 @@
-// See LICENSE for license details.
-
-package firrtl.annotations.transforms
-
-import firrtl.Mappers._
-import firrtl.analyses.InstanceGraph
-import firrtl.annotations.TargetToken.{Instance, OfModule}
-import firrtl.annotations.analysis.DuplicationHelper
-import firrtl.annotations._
-import firrtl.ir._
-import firrtl.{CircuitForm, CircuitState, FIRRTLException, HighForm, RenameMap, Transform, WDefInstance}
-
-import scala.collection.mutable
-
-
-/** Group of targets that should become local targets
- * @param targets
- */
-case class ResolvePaths(targets: Seq[CompleteTarget]) extends Annotation {
- override def update(renames: RenameMap): Seq[Annotation] = {
- val newTargets = targets.flatMap(t => renames.get(t).getOrElse(Seq(t)))
- Seq(ResolvePaths(newTargets))
- }
-}
-
-case class NoSuchTargetException(message: String) extends FIRRTLException(message)
-
-/** For a set of non-local targets, modify the instance/module hierarchy of the circuit such that
- * the paths in each non-local target can be removed
- *
- * In other words, if targeting a specific instance of a module, duplicate that module with a unique name
- * and instantiate the new module instead.
- *
- * Consumes [[ResolvePaths]]
- *
- * E.g. for non-local target A/b:B/c:C/d, rename the following
- * A/b:B/c:C/d -> C_/d
- * A/b:B/c:C -> B_/c:C_
- * A/b:B -> A/b:B_
- * B/x -> (B/x, B_/x) // where x is any reference in B
- * C/x -> (C/x, C_/x) // where x is any reference in C
- */
-class EliminateTargetPaths extends Transform {
-
- def inputForm: CircuitForm = HighForm
-
- def outputForm: CircuitForm = HighForm
-
- /** Replaces old ofModules with new ofModules by calling dupMap methods
- * Updates oldUsedOfModules, newUsedOfModules
- * @param originalModule Original name of this module
- * @param newModule New name of this module
- * @param s
- * @return
- */
- private def onStmt(dupMap: DuplicationHelper,
- oldUsedOfModules: mutable.HashSet[String],
- newUsedOfModules: mutable.HashSet[String])
- (originalModule: String, newModule: String)
- (s: Statement): Statement = s match {
- case d@DefInstance(_, name, module) =>
- val ofModule = dupMap.getNewOfModule(originalModule, newModule, Instance(name), OfModule(module)).value
- newUsedOfModules += ofModule
- oldUsedOfModules += module
- d.copy(module = ofModule)
- case d@WDefInstance(_, name, module, _) =>
- val ofModule = dupMap.getNewOfModule(originalModule, newModule, Instance(name), OfModule(module)).value
- newUsedOfModules += ofModule
- oldUsedOfModules += module
- d.copy(module = ofModule)
- case other => other map onStmt(dupMap, oldUsedOfModules, newUsedOfModules)(originalModule, newModule)
- }
-
- /** Returns a modified circuit and [[RenameMap]] containing the associated target remapping
- * @param cir
- * @param targets
- * @return
- */
- def run(cir: Circuit, targets: Seq[IsMember]): (Circuit, RenameMap) = {
-
- val dupMap = DuplicationHelper(cir.modules.map(_.name).toSet)
-
- // For each target, record its path and calculate the necessary modifications to circuit
- targets.foreach { t => dupMap.expandHierarchy(t) }
-
- // Records original list of used ofModules
- val oldUsedOfModules = mutable.HashSet[String]()
- oldUsedOfModules += cir.main
-
- // Records new list of used ofModules
- val newUsedOfModules = mutable.HashSet[String]()
- newUsedOfModules += cir.main
-
- // Contains new list of module declarations
- val duplicatedModuleList = mutable.ArrayBuffer[DefModule]()
-
- // Foreach module, calculate the unique names of its duplicates
- // Then, update the ofModules of instances that it encapsulates
- cir.modules.foreach { m =>
- dupMap.getDuplicates(m.name).foreach { newName =>
- val newM = m match {
- case e: ExtModule => e.copy(name = newName)
- case o: Module =>
- o.copy(name = newName, body = onStmt(dupMap, oldUsedOfModules, newUsedOfModules)(m.name, newName)(o.body))
- }
- duplicatedModuleList += newM
- }
- }
-
- // Calculate the final module list
- // A module is in the final list if:
- // 1) it is a module that is instantiated (new or old)
- // 2) it is an old module that was not instantiated and is still not instantiated
- val finalModuleList = duplicatedModuleList.filter(m =>
- newUsedOfModules.contains(m.name) || (!newUsedOfModules.contains(m.name) && !oldUsedOfModules.contains(m.name))
- )
-
- // Records how targets have been renamed
- val renameMap = RenameMap()
-
- // Foreach target, calculate the pathless version and only rename targets that are instantiated
- targets.foreach { t =>
- val newTsx = dupMap.makePathless(t)
- val newTs = newTsx.filter(c => newUsedOfModules.contains(c.moduleOpt.get))
- if(newTs.nonEmpty) {
- renameMap.record(t, newTs)
- }
- }
-
- // Return modified circuit and associated renameMap
- (cir.copy(modules = finalModuleList), renameMap)
- }
-
- override protected def execute(state: CircuitState): CircuitState = {
-
- val annotations = state.annotations.collect { case a: ResolvePaths => a }
-
- // Collect targets that are not local
- val targets = annotations.flatMap(_.targets.collect { case x: IsMember => x })
-
- // Check validity of paths in targets
- val instanceOfModules = new InstanceGraph(state.circuit).getChildrenInstanceOfModule
- val targetsWithInvalidPaths = mutable.ArrayBuffer[IsMember]()
- targets.foreach { t =>
- val path = t match {
- case m: ModuleTarget => Nil
- case i: InstanceTarget => i.asPath
- case r: ReferenceTarget => r.path
- }
- path.foldLeft(t.module) { case (module, (inst: Instance, of: OfModule)) =>
- val childrenOpt = instanceOfModules.get(module)
- if(childrenOpt.isEmpty || !childrenOpt.get.contains((inst, of))) {
- targetsWithInvalidPaths += t
- }
- of.value
- }
- }
- if(targetsWithInvalidPaths.nonEmpty) {
- val string = targetsWithInvalidPaths.mkString(",")
- throw NoSuchTargetException(s"""Some targets have illegal paths that cannot be resolved/eliminated: $string""")
- }
-
- val (newCircuit, renameMap) = run(state.circuit, targets)
-
- state.copy(circuit = newCircuit, renames = Some(renameMap))
- }
-}