aboutsummaryrefslogtreecommitdiff
path: root/src/main
diff options
context:
space:
mode:
authorJack Koenig2018-02-27 18:07:11 -0800
committerGitHub2018-02-27 18:07:11 -0800
commitc7eb1570dfb1c7701ea32d1209982a053f3cec1d (patch)
tree3f509b202d82841c5dad5588d1f953a25d389b44 /src/main
parentb90fc784a1819c1d7905910130a7da022214bc22 (diff)
Refactor Annotations (#721)
- Old Annotation renamed to deprecated LegacyAnnotation - Annotation is now a trait that can be extended - New JsonProtocol for Annotation [de]serialization - Replace AnnotationMap with AnnotationSeq - Deprecate Transform.getMyAnnotations - Update Transforms - Turn on deprecation warnings - Remove deprecated Driver.compile - Make AnnotationTests abstract with Legacy and Json subclasses - Add functionality to convert LegacyAnnotations of built-in annos This will give a noisy warning and is more of a best effort than a robust solution. Fixes #475 Closes #609
Diffstat (limited to 'src/main')
-rw-r--r--src/main/scala/firrtl/Compiler.scala74
-rw-r--r--src/main/scala/firrtl/Driver.scala99
-rw-r--r--src/main/scala/firrtl/Emitter.scala103
-rw-r--r--src/main/scala/firrtl/ExecutionOptionsManager.scala10
-rw-r--r--src/main/scala/firrtl/annotations/Annotation.scala169
-rw-r--r--src/main/scala/firrtl/annotations/AnnotationUtils.scala11
-rw-r--r--src/main/scala/firrtl/annotations/AnnotationYamlProtocol.scala13
-rw-r--r--src/main/scala/firrtl/annotations/JsonProtocol.scala84
-rw-r--r--src/main/scala/firrtl/annotations/Named.scala1
-rw-r--r--src/main/scala/firrtl/package.scala8
-rw-r--r--src/main/scala/firrtl/passes/Inline.scala26
-rw-r--r--src/main/scala/firrtl/passes/clocklist/ClockList.scala2
-rw-r--r--src/main/scala/firrtl/passes/clocklist/ClockListTransform.scala37
-rw-r--r--src/main/scala/firrtl/passes/memlib/DecorateMems.scala4
-rw-r--r--src/main/scala/firrtl/passes/memlib/InferReadWrite.scala19
-rw-r--r--src/main/scala/firrtl/passes/memlib/ReplaceMemMacros.scala35
-rw-r--r--src/main/scala/firrtl/passes/memlib/ReplaceMemTransform.scala38
-rw-r--r--src/main/scala/firrtl/passes/memlib/ResolveMemoryReference.scala18
-rw-r--r--src/main/scala/firrtl/passes/wiring/WiringTransform.scala78
-rw-r--r--src/main/scala/firrtl/transforms/BlackBoxSourceHelper.scala131
-rw-r--r--src/main/scala/firrtl/transforms/CheckCombLoops.scala14
-rw-r--r--src/main/scala/firrtl/transforms/ConstantPropagation.scala7
-rw-r--r--src/main/scala/firrtl/transforms/DeadCodeElimination.scala25
-rw-r--r--src/main/scala/firrtl/transforms/Dedup.scala12
-rw-r--r--src/main/scala/firrtl/transforms/Flatten.scala14
-rw-r--r--src/main/scala/firrtl/transforms/OptimizationAnnotations.scala33
26 files changed, 526 insertions, 539 deletions
diff --git a/src/main/scala/firrtl/Compiler.scala b/src/main/scala/firrtl/Compiler.scala
index 504ec85c..d43f415a 100644
--- a/src/main/scala/firrtl/Compiler.scala
+++ b/src/main/scala/firrtl/Compiler.scala
@@ -97,12 +97,12 @@ final class RenameMap private () {
}.mkString("\n")
}
-/**
- * Container of all annotations for a Firrtl compiler.
- */
-case class AnnotationMap(annotations: Seq[Annotation]) {
- def get(id: Class[_]): Seq[Annotation] = annotations.filter(a => a.transform == id)
- def get(named: Named): Seq[Annotation] = annotations.filter(n => n == named)
+/** Container of all annotations for a Firrtl compiler */
+class AnnotationSeq private (private[firrtl] val underlying: List[Annotation]) {
+ def toSeq: Seq[Annotation] = underlying.toSeq
+}
+object AnnotationSeq {
+ def apply(xs: Seq[Annotation]) = new AnnotationSeq(xs.toList)
}
/** Current State of the Circuit
@@ -117,8 +117,8 @@ case class AnnotationMap(annotations: Seq[Annotation]) {
case class CircuitState(
circuit: Circuit,
form: CircuitForm,
- annotations: Option[AnnotationMap] = None,
- renames: Option[RenameMap] = None) {
+ annotations: AnnotationSeq,
+ renames: Option[RenameMap]) {
/** Helper for getting just an emitted circuit */
def emittedCircuitOption: Option[EmittedCircuit] =
@@ -130,20 +130,15 @@ case class CircuitState(
throw new FIRRTLException(s"No EmittedCircuit found! Did you delete any annotations?\n$deletedAnnotations")
}
/** Helper function for extracting emitted components from annotations */
- def emittedComponents: Seq[EmittedComponent] = {
- val emittedOpt = annotations map (_.annotations collect {
- case EmittedCircuitAnnotation(x) => x
- case EmittedModuleAnnotation(x) => x
- })
- emittedOpt.getOrElse(Seq.empty)
- }
- def deletedAnnotations: Seq[Annotation] = {
- val deletedOpt = annotations map (_.annotations collect {
- case DeletedAnnotation(xformName, anno) =>
- DeletedAnnotation(xformName, anno)
- })
- deletedOpt.getOrElse(Seq.empty)
- }
+ def emittedComponents: Seq[EmittedComponent] =
+ annotations.collect { case emitted: EmittedAnnotation[_] => emitted.value }
+ def deletedAnnotations: Seq[Annotation] =
+ annotations.collect { case anno: DeletedAnnotation => anno }
+}
+object CircuitState {
+ def apply(circuit: Circuit, form: CircuitForm): CircuitState = apply(circuit, form, Seq())
+ def apply(circuit: Circuit, form: CircuitForm, annotations: AnnotationSeq) =
+ new CircuitState(circuit, form, annotations, None)
}
/** Current form of the Firrtl Circuit
@@ -222,15 +217,19 @@ abstract class Transform extends LazyLogging {
* @return A transformed Firrtl AST
*/
protected def execute(state: CircuitState): CircuitState
+
/** Convenience method to get annotations relevant to this Transform
*
* @param state The [[CircuitState]] form which to extract annotations
* @return A collection of annotations
*/
- final def getMyAnnotations(state: CircuitState): Seq[Annotation] = state.annotations match {
- case Some(annotations) => annotations.get(this.getClass) //TODO(azidar): ++ annotations.get(classOf[Transform])
- case None => Nil
+ @deprecated("Just collect the actual Annotation types the transform wants", "1.1")
+ final def getMyAnnotations(state: CircuitState): Seq[Annotation] = {
+ val msg = "getMyAnnotations is deprecated, use collect and match on concrete types"
+ Driver.dramaticWarning(msg)
+ state.annotations.collect { case a: LegacyAnnotation if a.transform == this.getClass => a }
}
+
/** Perform the transform and update annotations.
*
* @param state Input Firrtl AST
@@ -253,23 +252,23 @@ abstract class Transform extends LazyLogging {
}
logger.trace(s"Circuit:\n${result.circuit.serialize}")
logger.info(s"======== Finished Transform $name ========\n")
- CircuitState(result.circuit, result.form, Some(AnnotationMap(remappedAnnotations)), None)
+ CircuitState(result.circuit, result.form, remappedAnnotations, None)
}
/** Propagate annotations and update their names.
*
- * @param inAnno input AnnotationMap
- * @param resAnno result AnnotationMap
+ * @param inAnno input AnnotationSeq
+ * @param resAnno result AnnotationSeq
* @param renameOpt result RenameMap
* @return the updated annotations
*/
final private def propagateAnnotations(
- inAnno: Option[AnnotationMap],
- resAnno: Option[AnnotationMap],
- renameOpt: Option[RenameMap]): Seq[Annotation] = {
+ inAnno: AnnotationSeq,
+ resAnno: AnnotationSeq,
+ renameOpt: Option[RenameMap]): AnnotationSeq = {
val newAnnotations = {
- val inSet = inAnno.getOrElse(AnnotationMap(Seq.empty)).annotations.toSet
- val resSet = resAnno.getOrElse(AnnotationMap(Seq.empty)).annotations.toSet
+ val inSet = inAnno.toSet
+ val resSet = resAnno.toSet
val deleted = (inSet -- resSet).map {
case DeletedAnnotation(xFormName, delAnno) => DeletedAnnotation(s"$xFormName+$name", delAnno)
case anno => DeletedAnnotation(name, anno)
@@ -283,7 +282,7 @@ abstract class Transform extends LazyLogging {
val renames = renameOpt.getOrElse(RenameMap())
for {
anno <- newAnnotations.toSeq
- newAnno <- anno.update(renames.get(anno.target).getOrElse(Seq(anno.target)))
+ newAnno <- anno.update(renames)
} yield newAnno
}
}
@@ -437,12 +436,7 @@ trait Compiler extends LazyLogging {
def compileAndEmit(state: CircuitState,
customTransforms: Seq[Transform] = Seq.empty): CircuitState = {
val emitAnno = EmitCircuitAnnotation(emitter.getClass)
- // TODO This is ridiculous. Fix Annotations
- val annotations = state.annotations.map(_.annotations).getOrElse(Seq.empty)
- val annotationMap = AnnotationMap(annotations :+ emitAnno)
-
- // Run compiler
- compile(state.copy(annotations = Some(annotationMap)), customTransforms)
+ compile(state.copy(annotations = emitAnno +: state.annotations), customTransforms)
}
/** Perform compilation
diff --git a/src/main/scala/firrtl/Driver.scala b/src/main/scala/firrtl/Driver.scala
index 3c6f687f..77412a0e 100644
--- a/src/main/scala/firrtl/Driver.scala
+++ b/src/main/scala/firrtl/Driver.scala
@@ -5,6 +5,7 @@ package firrtl
import scala.collection._
import scala.io.Source
import scala.sys.process.{BasicIO,stringSeqToProcess}
+import scala.util.{Try, Success, Failure}
import scala.util.control.ControlThrowable
import java.io.{File, FileNotFoundException}
@@ -41,44 +42,6 @@ import firrtl.Utils.throwInternalError
*/
object Driver {
- //noinspection ScalaDeprecation
- // Compiles circuit. First parses a circuit from an input file,
- // executes all compiler passes, and writes result to an output
- // file.
- @deprecated("Please use execute", "firrtl 1.0")
- def compile(
- input: String,
- output: String,
- compiler: Compiler,
- infoMode: InfoMode = IgnoreInfo,
- customTransforms: Seq[Transform] = Seq.empty,
- annotations: AnnotationMap = AnnotationMap(Seq.empty)
- ): String = {
- val outputBuffer = new java.io.CharArrayWriter
- try {
- val parsedInput = Parser.parse(Source.fromFile(input).getLines(), infoMode)
- compiler.compile(
- CircuitState(parsedInput, ChirrtlForm, Some(annotations)),
- outputBuffer,
- customTransforms)
- }
-
- catch {
- // Rethrow the exceptions which are expected or due to the runtime environment (out of memory, stack overflow)
- case p: ControlThrowable => throw p
- case p: PassException => throw p
- case p: FIRRTLException => throw p
- // Treat remaining exceptions as internal errors.
- case e: Exception => throwInternalError(exception = Some(e))
- }
-
- val outputFile = new java.io.PrintWriter(output)
- val outputString = outputBuffer.toString
- outputFile.write(outputString)
- outputFile.close()
- outputString
- }
-
/** Print a warning message
*
* @param message error message
@@ -155,26 +118,35 @@ object Driver {
if (!file.exists) {
throw new FileNotFoundException(s"Annotation file $file not found!")
}
- val yaml = io.Source.fromFile(file).getLines().mkString("\n").parseYaml
- yaml.convertTo[List[Annotation]]
-
+ // Try new protocol first
+ JsonProtocol.deserializeTry(file).getOrElse {
+ val annos = Try {
+ val yaml = io.Source.fromFile(file).getLines().mkString("\n").parseYaml
+ yaml.convertTo[List[LegacyAnnotation]]
+ }
+ annos match {
+ case Success(result) =>
+ val msg = s"$file is a YAML file!\n" +
+ (" "*9) + "YAML Annotation files are deprecated! Use JSON"
+ Driver.dramaticWarning(msg)
+ result
+ case Failure(_) => throw new InvalidAnnotationFileException(file.toString)
+ }
+ }
}
- val targetDirAnno =
- List(Annotation(
- CircuitName("All"),
- classOf[BlackBoxSourceHelper],
- BlackBoxTargetDir(optionsManager.targetDirName).serialize
- ))
+ val targetDirAnno = List(BlackBoxTargetDirAnno(optionsManager.targetDirName))
// Output Annotations
val outputAnnos = firrtlConfig.getEmitterAnnos(optionsManager)
val globalAnnos = Seq(TargetDirAnnotation(optionsManager.targetDirName)) ++
- (if (firrtlConfig.dontCheckCombLoops) Seq(DontCheckCombLoopsAnnotation()) else Seq()) ++
- (if (firrtlConfig.noDCE) Seq(NoDCEAnnotation()) else Seq())
+ (if (firrtlConfig.dontCheckCombLoops) Seq(DontCheckCombLoopsAnnotation) else Seq()) ++
+ (if (firrtlConfig.noDCE) Seq(NoDCEAnnotation) else Seq())
- targetDirAnno ++ outputAnnos ++ globalAnnos ++ firrtlConfig.annotations ++ loadedAnnos
+ val annos = targetDirAnno ++ outputAnnos ++ globalAnnos ++
+ firrtlConfig.annotations ++ loadedAnnos
+ LegacyAnnotation.convertLegacyAnnos(annos)
}
/**
@@ -229,21 +201,18 @@ object Driver {
optionsManager.makeTargetDir()
maybeFinalState = Some(firrtlConfig.compiler.compile(
- CircuitState(parsedInput,
- ChirrtlForm,
- Some(AnnotationMap(annos))),
+ CircuitState(parsedInput, ChirrtlForm, annos),
firrtlConfig.customTransforms
))
}
-
- catch {
- // Rethrow the exceptions which are expected or due to the runtime environment (out of memory, stack overflow)
- case p: ControlThrowable => throw p
- case p: PassException => throw p
- case p: FIRRTLException => throw p
- // Treat remaining exceptions as internal errors.
- case e: Exception => throwInternalError(exception = Some(e))
- }
+ catch {
+ // Rethrow the exceptions which are expected or due to the runtime environment (out of memory, stack overflow)
+ case p: ControlThrowable => throw p
+ case p: PassException => throw p
+ case p: FIRRTLException => throw p
+ // Treat remaining exceptions as internal errors.
+ case e: Exception => throwInternalError(exception = Some(e))
+ }
val finalState = maybeFinalState.get
@@ -273,11 +242,9 @@ object Driver {
optionsManager.firrtlOptions.outputAnnotationFileName match {
case "" =>
case file =>
- val filename = optionsManager.getBuildFileName("anno", file)
+ val filename = optionsManager.getBuildFileName("anno.json", file)
val outputFile = new java.io.PrintWriter(filename)
- finalState.annotations.foreach {
- finalAnnos => outputFile.write(finalAnnos.annotations.toYaml.prettyPrint)
- }
+ outputFile.write(JsonProtocol.serialize(finalState.annotations))
outputFile.close()
}
diff --git a/src/main/scala/firrtl/Emitter.scala b/src/main/scala/firrtl/Emitter.scala
index cf356dcb..a94ed37f 100644
--- a/src/main/scala/firrtl/Emitter.scala
+++ b/src/main/scala/firrtl/Emitter.scala
@@ -24,18 +24,11 @@ import scala.collection.mutable.{ArrayBuffer, LinkedHashMap, HashSet}
case class EmitterException(message: String) extends PassException(message)
// ***** Annotations for telling the Emitters what to emit *****
-sealed abstract class EmitAnnotation(marker: String) {
- // TODO Is there a better way to do Name to indicate don't care?
- def apply(transform: Class[_ <: Transform]): Annotation =
- Annotation(CircuitTopName, transform, marker)
- def unapply(a: Annotation): Boolean = a match {
- // Assumes transform is already filtered appropriately
- case Annotation(CircuitTopName, _, str) if str == marker => true
- case _ => false
- }
+sealed trait EmitAnnotation extends NoTargetAnnotation {
+ val emitter: Class[_ <: Emitter]
}
-object EmitCircuitAnnotation extends EmitAnnotation("emitCircuit")
-object EmitAllModulesAnnotation extends EmitAnnotation("emitAllModules")
+case class EmitCircuitAnnotation(emitter: Class[_ <: Emitter]) extends EmitAnnotation
+case class EmitAllModulesAnnotation(emitter: Class[_ <: Emitter]) extends EmitAnnotation
// ***** Annotations for results of emission *****
sealed abstract class EmittedComponent {
@@ -49,60 +42,22 @@ sealed abstract class EmittedModule extends EmittedComponent
final case class EmittedFirrtlModule(name: String, value: String) extends EmittedModule
final case class EmittedVerilogModule(name: String, value: String) extends EmittedModule
-/** Super class for Annotations containing emitted components
- *
- * @note These annotations cannot be serialized and deserialized to/from an annotation file
- */
-sealed abstract class EmittedAnnotation[T <: EmittedComponent](marker: String) {
- // Private datastructure to hold the actual emitted objects
- // TODO Once annotations can contain arbitrary datastructures, get rid of this
- private val emittedBuffer = mutable.ArrayBuffer.empty[T]
-
- def apply(value: T): Annotation = {
- // Synchronize because of multithreading
- // This doesn't happen often, shouldn't be a big deal for performance
- val idx = emittedBuffer.synchronized {
- emittedBuffer += value
- emittedBuffer.size - 1
- }
- Annotation(CircuitTopName, classOf[Transform], s"$marker:$idx")
- }
- def unapply(a: Annotation): Option[T] = a match {
- // assume transform has been filtered
- case Annotation(CircuitTopName, _, str) if str.startsWith(marker) =>
- val idx = str.stripPrefix(s"$marker:").toInt
- Some(emittedBuffer(idx))
- case _ => None
- }
+/** Traits for Annotations containing emitted components */
+sealed trait EmittedAnnotation[T <: EmittedComponent] extends NoTargetAnnotation {
+ val value: T
}
+sealed trait EmittedCircuitAnnotation[T <: EmittedCircuit] extends EmittedAnnotation[T]
+sealed trait EmittedModuleAnnotation[T <: EmittedModule] extends EmittedAnnotation[T]
-object EmittedFirrtlCircuitAnnotation extends EmittedAnnotation[EmittedFirrtlCircuit]("emittedFirrtlCircuit")
-object EmittedVerilogCircuitAnnotation extends EmittedAnnotation[EmittedVerilogCircuit]("emittedVerilogCircuit")
-object EmittedCircuitAnnotation {
- def apply(value: EmittedCircuit): Annotation = value match {
- case firrtl: EmittedFirrtlCircuit => EmittedFirrtlCircuitAnnotation(firrtl)
- case verilog: EmittedVerilogCircuit => EmittedVerilogCircuitAnnotation(verilog)
- }
- def unapply(a: Annotation): Option[EmittedCircuit] = a match {
- case EmittedFirrtlCircuitAnnotation(x) => Some(x)
- case EmittedVerilogCircuitAnnotation(x) => Some(x)
- case _ => None
- }
-}
-object EmittedFirrtlModuleAnnotation extends EmittedAnnotation[EmittedFirrtlModule]("emittedFirrtlModule")
-object EmittedVerilogModuleAnnotation extends EmittedAnnotation[EmittedVerilogModule]("emittedVerilogModule")
-object EmittedModuleAnnotation {
- def apply(value: EmittedModule): Annotation = value match {
- case firrtl: EmittedFirrtlModule => EmittedFirrtlModuleAnnotation(firrtl)
- case verilog: EmittedVerilogModule => EmittedVerilogModuleAnnotation(verilog)
- }
- def unapply(a: Annotation): Option[EmittedModule] = a match {
- case EmittedFirrtlModuleAnnotation(x) => Some(x)
- case EmittedVerilogModuleAnnotation(x) => Some(x)
- case _ => None
- }
-}
+case class EmittedFirrtlCircuitAnnotation(value: EmittedFirrtlCircuit)
+ extends EmittedCircuitAnnotation[EmittedFirrtlCircuit]
+case class EmittedVerilogCircuitAnnotation(value: EmittedVerilogCircuit)
+ extends EmittedCircuitAnnotation[EmittedVerilogCircuit]
+case class EmittedFirrtlModuleAnnotation(value: EmittedFirrtlModule)
+ extends EmittedModuleAnnotation[EmittedFirrtlModule]
+case class EmittedVerilogModuleAnnotation(value: EmittedVerilogModule)
+ extends EmittedModuleAnnotation[EmittedVerilogModule]
sealed abstract class FirrtlEmitter(form: CircuitForm) extends Transform with Emitter {
def inputForm = form
@@ -140,19 +95,15 @@ sealed abstract class FirrtlEmitter(form: CircuitForm) extends Transform with Em
}
override def execute(state: CircuitState): CircuitState = {
- val newAnnos = getMyAnnotations(state).flatMap {
- case EmitCircuitAnnotation() =>
+ val newAnnos = state.annotations.flatMap {
+ case EmitCircuitAnnotation(_) =>
Seq(EmittedFirrtlCircuitAnnotation.apply(
EmittedFirrtlCircuit(state.circuit.main, state.circuit.serialize)))
- case EmitAllModulesAnnotation() =>
+ case EmitAllModulesAnnotation(_) =>
emitAllModules(state.circuit) map (EmittedFirrtlModuleAnnotation(_))
case _ => Seq()
}
- val annos = newAnnos ++ (state.annotations match {
- case None => Seq.empty
- case Some(a) => a.annotations
- })
- state.copy(annotations = Some(AnnotationMap(annos)))
+ state.copy(annotations = newAnnos ++ state.annotations)
}
// Old style, deprecated
@@ -750,13 +701,13 @@ class VerilogEmitter extends SeqTransform with Emitter {
}
override def execute(state: CircuitState): CircuitState = {
- val newAnnos = getMyAnnotations(state).flatMap {
- case EmitCircuitAnnotation() =>
+ val newAnnos = state.annotations.flatMap {
+ case EmitCircuitAnnotation(_) =>
val writer = new java.io.StringWriter
emit(state, writer)
Seq(EmittedVerilogCircuitAnnotation(EmittedVerilogCircuit(state.circuit.main, writer.toString)))
- case EmitAllModulesAnnotation() =>
+ case EmitAllModulesAnnotation(_) =>
val circuit = runTransforms(state).circuit
val moduleMap = circuit.modules.map(m => m.name -> m).toMap
@@ -769,10 +720,6 @@ class VerilogEmitter extends SeqTransform with Emitter {
}
case _ => Seq()
}
- val annos = newAnnos ++ (state.annotations match {
- case None => Seq.empty
- case Some(a) => a.annotations
- })
- state.copy(annotations = Some(AnnotationMap(annos)))
+ state.copy(annotations = newAnnos ++ state.annotations)
}
}
diff --git a/src/main/scala/firrtl/ExecutionOptionsManager.scala b/src/main/scala/firrtl/ExecutionOptionsManager.scala
index de5c9898..1aac0ad6 100644
--- a/src/main/scala/firrtl/ExecutionOptionsManager.scala
+++ b/src/main/scala/firrtl/ExecutionOptionsManager.scala
@@ -67,8 +67,8 @@ case class CommonOptions(
}
}
-/** [[annotations.GlobalCircuitAnnotation]] that contains the [[CommonOptions]] target directory */
-object TargetDirAnnotation extends GlobalCircuitAnnotation
+/** Annotation that contains the [[CommonOptions]] target directory */
+case class TargetDirAnnotation(value: String) extends SingleStringAnnotation
trait HasCommonOptions {
self: ExecutionOptionsManager =>
@@ -408,7 +408,7 @@ trait HasFirrtlOptions {
.valueName ("<circuit>")
.foreach { x =>
firrtlOptions = firrtlOptions.copy(
- annotations = firrtlOptions.annotations :+ InferReadWriteAnnotation(x),
+ annotations = firrtlOptions.annotations :+ InferReadWriteAnnotation,
customTransforms = firrtlOptions.customTransforms :+ new passes.memlib.InferReadWrite
)
}.text {
@@ -420,7 +420,7 @@ trait HasFirrtlOptions {
.valueName ("-c:<circuit>:-i:<filename>:-o:<filename>")
.foreach { x =>
firrtlOptions = firrtlOptions.copy(
- annotations = firrtlOptions.annotations :+ ReplSeqMemAnnotation(x),
+ annotations = firrtlOptions.annotations :+ ReplSeqMemAnnotation.parse(x),
customTransforms = firrtlOptions.customTransforms :+ new passes.memlib.ReplSeqMem
)
}
@@ -433,7 +433,7 @@ trait HasFirrtlOptions {
.valueName ("-c:<circuit>:-m:<module>:-o:<filename>")
.foreach { x =>
firrtlOptions = firrtlOptions.copy(
- annotations = firrtlOptions.annotations :+ ClockListAnnotation(x),
+ annotations = firrtlOptions.annotations :+ ClockListAnnotation.parse(x),
customTransforms = firrtlOptions.customTransforms :+ new passes.clocklist.ClockListTransform
)
}
diff --git a/src/main/scala/firrtl/annotations/Annotation.scala b/src/main/scala/firrtl/annotations/Annotation.scala
index f96724c6..b16509a1 100644
--- a/src/main/scala/firrtl/annotations/Annotation.scala
+++ b/src/main/scala/firrtl/annotations/Annotation.scala
@@ -8,16 +8,80 @@ import firrtl.annotations.AnnotationYamlProtocol._
case class AnnotationException(message: String) extends Exception(message)
-final case class Annotation(target: Named, transform: Class[_ <: Transform], value: String) {
+/** Base type of auxiliary information */
+trait Annotation {
+ /** Update the target based on how signals are renamed */
+ def update(renames: RenameMap): Seq[Annotation]
+
+ /** Pretty Print
+ *
+ * @note In [[logger.LogLevel.Debug]] this is called on every Annotation after every Transform
+ */
+ def serialize: String = this.toString
+}
+
+/** 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)
+}
+
+/** An Annotation that targets a single [[Named]] thing */
+trait SingleTargetAnnotation[T <: Named] extends Annotation {
+ val target: T
+
+ /** 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] =
+ 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))
+}
+
+trait SingleStringAnnotation extends NoTargetAnnotation {
+ def value: String
+}
+
+object Annotation {
+ @deprecated("This returns a LegacyAnnotation, use an explicit Annotation type", "1.1")
+ 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)] =
+ Some((a.target, a.transform, a.value))
+}
+
+// Constructor is private so that we can still construct these internally without deprecation
+// warnings
+final case class LegacyAnnotation private[firrtl] (
+ target: Named,
+ transform: Class[_ <: Transform],
+ value: String) extends SingleTargetAnnotation[Named] {
val targetString: String = target.serialize
val transformClass: String = transform.getName
+ def targets(named: Named): Boolean = named == target
+ def targets(transform: Class[_ <: Transform]): Boolean = transform == this.transform
+
/**
* This serialize is basically a pretty printer, actual serialization is handled by
* AnnotationYamlProtocol
* @return a nicer string than the raw case class default
*/
- def serialize: String = {
+ override def serialize: String = {
s"Annotation(${target.serialize},${transform.getCanonicalName},$value)"
}
@@ -27,34 +91,89 @@ final case class Annotation(target: Named, transform: Class[_ <: Transform], val
}
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) = Annotation(n, transform, value)
+ def duplicate(n: Named) = new LegacyAnnotation(n, transform, value)
}
-object DeletedAnnotation {
- def apply(xFormName: String, anno: Annotation): Annotation =
- Annotation(anno.target, classOf[Transform], s"""DELETED by $xFormName\n${AnnotationUtils.toYaml(anno)}""")
+// 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) =
+ throw new Exception(s"Old-style annotations that look like $name are no longer supported")
+
+ private val OldDeletedRegex = """(?s)DELETED by ([^\n]*)\n(.*)""".r
+ private val PinsRegex = "pins:(.*)".r
+ private val SourceRegex = "source (.+)".r
+ private val SinkRegex = "sink (.+)".r
- private val deletedRegex = """(?s)DELETED by ([^\n]*)\n(.*)""".r
- def unapply(a: Annotation): Option[(String, Annotation)] = a match {
- case Annotation(named, t, deletedRegex(xFormName, annoString)) if t == classOf[Transform] =>
- Some((xFormName, AnnotationUtils.fromYaml(annoString)))
- case _ => None
+ import firrtl.transforms._
+ import firrtl.passes._
+ 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
+ def convertLegacyAnno(anno: LegacyAnnotation): Annotation = anno match {
+ // All old-style Emitter annotations are illegal
+ case LegacyAnnotation(_,_,"emitCircuit") => errorIllegalAnno("EmitCircuitAnnotation")
+ case LegacyAnnotation(_,_,"emitAllModules") => errorIllegalAnno("EmitAllModulesAnnotation")
+ case LegacyAnnotation(_,_,value) if value.startsWith("emittedFirrtlCircuit") =>
+ errorIllegalAnno("EmittedFirrtlCircuitAnnotation")
+ case LegacyAnnotation(_,_,value) if value.startsWith("emittedFirrtlModule") =>
+ errorIllegalAnno("EmittedFirrtlModuleAnnotation")
+ case LegacyAnnotation(_,_,value) if value.startsWith("emittedVerilogCircuit") =>
+ errorIllegalAnno("EmittedVerilogCircuitAnnotation")
+ case LegacyAnnotation(_,_,value) if value.startsWith("emittedVerilogModule") =>
+ errorIllegalAnno("EmittedVerilogModuleAnnotation")
+ // People shouldn't be trying to pass deleted annotations to Firrtl
+ case LegacyAnnotation(_,_,OldDeletedRegex(_,_)) => errorIllegalAnno("DeletedAnnotation")
+ // Some annotations we'll try to support
+ case LegacyAnnotation(named, t, _) if t == classOf[InlineInstances] => InlineAnnotation(named)
+ case LegacyAnnotation(n: ModuleName, t, outputConfig) if t == classOf[ClockListTransform] =>
+ ClockListAnnotation(n, outputConfig)
+ case LegacyAnnotation(CircuitName(_), transform, "") if transform == classOf[InferReadWrite] =>
+ InferReadWriteAnnotation
+ case LegacyAnnotation(_,_,PinsRegex(pins)) => PinAnnotation(pins.split(" "))
+ case LegacyAnnotation(_, t, value) if t == classOf[ReplSeqMem] =>
+ val args = value.split(" ")
+ require(args.size == 2, "Something went wrong, stop using legacy ReplSeqMemAnnotation")
+ ReplSeqMemAnnotation(args(0), args(1))
+ case LegacyAnnotation(c: ComponentName, transform, "nodedupmem!")
+ if transform == classOf[ResolveMemoryReference] => NoDedupMemAnnotation(c)
+ case LegacyAnnotation(m: ModuleName, transform, "nodedup!")
+ if transform == classOf[DedupModules] => NoDedupAnnotation(m)
+ 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 {
+ case "resource" :: id :: _ => BlackBoxResourceAnno(m, id)
+ case "inline" :: name :: text :: _ => BlackBoxInlineAnno(m, name, text)
+ case "targetDir" :: targetDir :: _ => BlackBoxTargetDirAnno(targetDir)
+ case _ => errorIllegalAnno("BlackBoxSourceAnnotation")
+ }
+ case LegacyAnnotation(_, transform, "noDCE!") if transform == classOf[DeadCodeElimination] =>
+ NoDCEAnnotation
+ case LegacyAnnotation(c: ComponentName, _, "DONTtouch!") => DontTouchAnnotation(c)
+ case LegacyAnnotation(c: ModuleName, _, "optimizableExtModule!") =>
+ OptimizableExtModuleAnnotation(c)
+ case other => other
+ }
+ def convertLegacyAnnos(annos: Seq[Annotation]): Seq[Annotation] = {
+ var warned: Boolean = false
+ annos.map {
+ case legacy: LegacyAnnotation =>
+ val annox = convertLegacyAnno(legacy)
+ if (!warned && (annox ne legacy)) {
+ val msg = s"A LegacyAnnotation was automatically converted.\n" + (" "*9) +
+ "This functionality will soon be removed. Please migrate to new annotations."
+ Driver.dramaticWarning(msg)
+ warned = true
+ }
+ annox
+ case other => other
+ }
}
}
-/** Parent class to create global annotations
- *
- * These annotations are Circuit-level and available to every transform
- */
-abstract class GlobalCircuitAnnotation {
- private lazy val marker = this.getClass.getName
- def apply(value: String): Annotation =
- Annotation(CircuitTopName, classOf[Transform], s"$marker:$value")
- def unapply(a: Annotation): Option[String] = a match {
- // Assumes transform is already filtered appropriately
- case Annotation(CircuitTopName, _, str) if str.startsWith(marker) =>
- Some(str.stripPrefix(s"$marker:"))
- case _ => None
- }
+case class DeletedAnnotation(xFormName: String, anno: Annotation) extends NoTargetAnnotation {
+ override def serialize: String = s"""DELETED by $xFormName\n${anno.serialize}"""
}
diff --git a/src/main/scala/firrtl/annotations/AnnotationUtils.scala b/src/main/scala/firrtl/annotations/AnnotationUtils.scala
index 240c46d6..0fc192a6 100644
--- a/src/main/scala/firrtl/annotations/AnnotationUtils.scala
+++ b/src/main/scala/firrtl/annotations/AnnotationUtils.scala
@@ -3,15 +3,22 @@
package firrtl
package annotations
+import org.json4s._
+import org.json4s.native.JsonMethods._
+import org.json4s.native.Serialization
+import org.json4s.native.Serialization.{read, write, writePretty}
+
import net.jcazevedo.moultingyaml._
import firrtl.annotations.AnnotationYamlProtocol._
import firrtl.ir._
import firrtl.Utils.error
+class InvalidAnnotationFileException(msg: String) extends Exception(msg)
+
object AnnotationUtils {
- def toYaml(a: Annotation): String = a.toYaml.prettyPrint
- def fromYaml(s: String): Annotation = s.parseYaml.convertTo[Annotation]
+ def toYaml(a: LegacyAnnotation): String = a.toYaml.prettyPrint
+ def fromYaml(s: String): LegacyAnnotation = s.parseYaml.convertTo[LegacyAnnotation]
/** Returns true if a valid Module name */
val SerializedModuleName = """([a-zA-Z_][a-zA-Z_0-9~!@#$%^*\-+=?/]*)""".r
diff --git a/src/main/scala/firrtl/annotations/AnnotationYamlProtocol.scala b/src/main/scala/firrtl/annotations/AnnotationYamlProtocol.scala
index 9018d494..e0337d6e 100644
--- a/src/main/scala/firrtl/annotations/AnnotationYamlProtocol.scala
+++ b/src/main/scala/firrtl/annotations/AnnotationYamlProtocol.scala
@@ -7,23 +7,24 @@ import net.jcazevedo.moultingyaml._
object AnnotationYamlProtocol extends DefaultYamlProtocol {
// bottom depends on top
- implicit object AnnotationYamlFormat extends YamlFormat[Annotation] {
- def write(a: Annotation) = YamlObject(
+ implicit object AnnotationYamlFormat extends YamlFormat[LegacyAnnotation] {
+ def write(a: LegacyAnnotation) = YamlObject(
YamlString("targetString") -> YamlString(a.targetString),
YamlString("transformClass") -> YamlString(a.transformClass),
YamlString("value") -> YamlString(a.value)
)
- def read(yamlValue: YamlValue): Annotation = {
+ def read(yamlValue: YamlValue): LegacyAnnotation = {
try {
yamlValue.asYamlObject.getFields(
YamlString("targetString"),
YamlString("transformClass"),
YamlString("value")) match {
case Seq(YamlString(targetString), YamlString(transformClass), YamlString(value)) =>
- Annotation(
- toTarget(targetString), Class.forName(transformClass).asInstanceOf[Class[_ <: Transform]], value)
- case _ => deserializationError("Annotation expected")
+ LegacyAnnotation(toTarget(targetString),
+ Class.forName(transformClass).asInstanceOf[Class[_ <: Transform]],
+ value)
+ case _ => deserializationError("LegacyAnnotation expected")
}
}
catch {
diff --git a/src/main/scala/firrtl/annotations/JsonProtocol.scala b/src/main/scala/firrtl/annotations/JsonProtocol.scala
new file mode 100644
index 00000000..5005ccb0
--- /dev/null
+++ b/src/main/scala/firrtl/annotations/JsonProtocol.scala
@@ -0,0 +1,84 @@
+
+package firrtl
+package annotations
+
+import scala.util.Try
+
+import org.json4s._
+import org.json4s.native.JsonMethods._
+import org.json4s.native.Serialization
+import org.json4s.native.Serialization.{read, write, writePretty}
+
+import firrtl.ir._
+import firrtl.Utils.error
+
+object JsonProtocol {
+
+ // Helper for error messages
+ private def prettifyJsonInput(in: JsonInput): String = {
+ def defaultToString(base: String, obj: Any): String = s"$base@${obj.hashCode.toHexString}"
+ in match {
+ case FileInput(file) => file.toString
+ case StringInput(o) => defaultToString("String", o)
+ case ReaderInput(o) => defaultToString("Reader", o)
+ case StreamInput(o) => defaultToString("Stream", o)
+ }
+ }
+
+ class TransformClassSerializer extends CustomSerializer[Class[_ <: Transform]](format => (
+ { case JString(s) => Class.forName(s).asInstanceOf[Class[_ <: Transform]] },
+ { case x: Class[_] => JString(x.getName) }
+ ))
+ // TODO Reduce boilerplate?
+ class NamedSerializer extends CustomSerializer[Named](format => (
+ { case JString(s) => AnnotationUtils.toNamed(s) },
+ { case named: Named => JString(named.serialize) }
+ ))
+ class CircuitNameSerializer extends CustomSerializer[CircuitName](format => (
+ { case JString(s) => AnnotationUtils.toNamed(s).asInstanceOf[CircuitName] },
+ { case named: CircuitName => JString(named.serialize) }
+ ))
+ class ModuleNameSerializer extends CustomSerializer[ModuleName](format => (
+ { case JString(s) => AnnotationUtils.toNamed(s).asInstanceOf[ModuleName] },
+ { case named: ModuleName => JString(named.serialize) }
+ ))
+ class ComponentNameSerializer extends CustomSerializer[ComponentName](format => (
+ { case JString(s) => AnnotationUtils.toNamed(s).asInstanceOf[ComponentName] },
+ { case named: ComponentName => 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
+ }
+
+ /** Serialize annotations to a String for emission */
+ def serialize(annos: Seq[Annotation]): String = serializeTry(annos).get
+
+ def serializeTry(annos: Seq[Annotation]): Try[String] = {
+ val tags = annos.map(_.getClass).distinct
+ implicit val formats = jsonFormat(tags)
+ Try(writePretty(annos))
+ }
+
+ def deserialize(in: JsonInput): Seq[Annotation] = deserializeTry(in).get
+
+ def deserializeTry(in: JsonInput): Try[Seq[Annotation]] = Try({
+ def throwError() = throw new InvalidAnnotationFileException(prettifyJsonInput(in))
+ val parsed = parse(in)
+ val annos = parsed match {
+ case JArray(objs) => objs
+ case _ => throwError()
+ }
+ // Gather classes so we can deserialize arbitrary Annotations
+ val classes = annos.map({
+ case JObject(("class", JString(c)) :: tail) => c
+ case _ => throwError()
+ }).distinct
+ val loaded = classes.map(Class.forName(_).asInstanceOf[Class[_ <: Annotation]])
+ implicit val formats = jsonFormat(loaded)
+ read[List[Annotation]](in)
+ })
+}
diff --git a/src/main/scala/firrtl/annotations/Named.scala b/src/main/scala/firrtl/annotations/Named.scala
index 0e365249..d3a70643 100644
--- a/src/main/scala/firrtl/annotations/Named.scala
+++ b/src/main/scala/firrtl/annotations/Named.scala
@@ -10,7 +10,6 @@ import AnnotationUtils.{validModuleName, validComponentName, toExp}
* Named classes associate an annotation with a component in a Firrtl circuit
*/
sealed trait Named {
- def name: String
def serialize: String
}
diff --git a/src/main/scala/firrtl/package.scala b/src/main/scala/firrtl/package.scala
new file mode 100644
index 00000000..c0b79462
--- /dev/null
+++ b/src/main/scala/firrtl/package.scala
@@ -0,0 +1,8 @@
+
+import firrtl.AnnotationSeq
+import firrtl.annotations.Annotation
+
+package object firrtl {
+ implicit def seqToAnnoSeq(xs: Seq[Annotation]) = AnnotationSeq(xs)
+ implicit def annoSeqToSeq(as: AnnotationSeq): Seq[Annotation] = as.underlying
+}
diff --git a/src/main/scala/firrtl/passes/Inline.scala b/src/main/scala/firrtl/passes/Inline.scala
index 2e15f09c..0ba0c5d9 100644
--- a/src/main/scala/firrtl/passes/Inline.scala
+++ b/src/main/scala/firrtl/passes/Inline.scala
@@ -10,14 +10,9 @@ import firrtl.annotations._
// Datastructures
import scala.collection.mutable
-// Tags an annotation to be consumed by this pass
-object InlineAnnotation {
- def apply(target: Named): Annotation = Annotation(target, classOf[InlineInstances], "")
-
- def unapply(a: Annotation): Option[Named] = a match {
- case Annotation(named, t, _) if t == classOf[InlineInstances] => Some(named)
- case _ => None
- }
+/** Indicates that something should be inlined */
+case class InlineAnnotation(target: Named) extends SingleTargetAnnotation[Named] {
+ def duplicate(n: Named) = InlineAnnotation(n)
}
// Only use on legal Firrtl. Specifically, the restriction of
@@ -37,18 +32,17 @@ class InlineInstances extends Transform {
}.toSet, instNames)
case InlineAnnotation(ModuleName(mod, cir)) => (modNames + ModuleName(mod, cir), instNames)
case InlineAnnotation(ComponentName(com, mod)) => (modNames, instNames + ComponentName(com, mod))
- case _ => throw new PassException("Annotation must be InlineAnnotation")
+ case _ => (modNames, instNames)
}
}
def execute(state: CircuitState): CircuitState = {
// TODO Add error check for more than one annotation for inlining
- // TODO Propagate other annotations
- getMyAnnotations(state) match {
- case Nil => CircuitState(state.circuit, state.form)
- case myAnnotations =>
- val (modNames, instNames) = collectAnns(state.circuit, myAnnotations)
- run(state.circuit, modNames, instNames, state.annotations)
+ val (modNames, instNames) = collectAnns(state.circuit, state.annotations)
+ if (modNames.nonEmpty || instNames.nonEmpty) {
+ run(state.circuit, modNames, instNames, state.annotations)
+ } else {
+ state
}
}
@@ -92,7 +86,7 @@ class InlineInstances extends Transform {
}
- def run(c: Circuit, modsToInline: Set[ModuleName], instsToInline: Set[ComponentName], annos: Option[AnnotationMap]): CircuitState = {
+ def run(c: Circuit, modsToInline: Set[ModuleName], instsToInline: Set[ComponentName], annos: AnnotationSeq): CircuitState = {
def getInstancesOf(c: Circuit, modules: Set[String]): Set[String] =
c.modules.foldLeft(Set[String]()) { (set, d) =>
d match {
diff --git a/src/main/scala/firrtl/passes/clocklist/ClockList.scala b/src/main/scala/firrtl/passes/clocklist/ClockList.scala
index be4d99fc..fcc3cd5e 100644
--- a/src/main/scala/firrtl/passes/clocklist/ClockList.scala
+++ b/src/main/scala/firrtl/passes/clocklist/ClockList.scala
@@ -43,7 +43,7 @@ class ClockList(top: String, writer: Writer) extends Pass {
// Inline the clock-only circuit up to the specified top module
val modulesToInline = (c.modules.collect { case Module(_, n, _, _) if n != top => ModuleName(n, CircuitName(c.main)) }).toSet
val inlineTransform = new InlineInstances
- val inlinedCircuit = inlineTransform.run(onlyClockCircuit, modulesToInline, Set(), None).circuit
+ val inlinedCircuit = inlineTransform.run(onlyClockCircuit, modulesToInline, Set(), Seq()).circuit
val topModule = inlinedCircuit.modules.find(_.name == top).getOrElse(throwInternalError(Some("no top module")))
// Build a hashmap of connections to use for getOrigins
diff --git a/src/main/scala/firrtl/passes/clocklist/ClockListTransform.scala b/src/main/scala/firrtl/passes/clocklist/ClockListTransform.scala
index 24f25525..6c7b2e18 100644
--- a/src/main/scala/firrtl/passes/clocklist/ClockListTransform.scala
+++ b/src/main/scala/firrtl/passes/clocklist/ClockListTransform.scala
@@ -15,8 +15,13 @@ import memlib.AnalysisUtils._
import memlib._
import Mappers._
+case class ClockListAnnotation(target: ModuleName, outputConfig: String) extends
+ SingleTargetAnnotation[ModuleName] {
+ def duplicate(n: ModuleName) = ClockListAnnotation(n, outputConfig)
+}
+
object ClockListAnnotation {
- def apply(t: String): Annotation = {
+ def parse(t: String): ClockListAnnotation = {
val usage = """
[Optional] ClockList
List which signal drives each clock of every descendent of specified module
@@ -45,16 +50,7 @@ Usage:
case None =>
}
val target = ModuleName(passModule, CircuitName(passCircuit))
- Annotation(target, classOf[ClockListTransform], outputConfig)
- }
-
- def apply(target: ModuleName, outputConfig: String): Annotation =
- Annotation(target, classOf[ClockListTransform], outputConfig)
-
- def unapply(a: Annotation): Option[(ModuleName, String)] = a match {
- case Annotation(ModuleName(m, c), t, outputConfig) if t == classOf[ClockListTransform] =>
- Some((ModuleName(m, c), outputConfig))
- case _ => None
+ ClockListAnnotation(target, outputConfig)
}
}
@@ -63,13 +59,16 @@ class ClockListTransform extends Transform {
def outputForm = LowForm
def passSeq(top: String, writer: Writer): Seq[Pass] =
Seq(new ClockList(top, writer))
- def execute(state: CircuitState): CircuitState = getMyAnnotations(state) match {
- case Seq(ClockListAnnotation(ModuleName(top, CircuitName(state.circuit.main)), out)) =>
- val outputFile = new PrintWriter(out)
- val newC = (new ClockList(top, outputFile)).run(state.circuit)
- outputFile.close()
- CircuitState(newC, state.form, state.annotations)
- case Nil => state
- case seq => error(s"Found illegal clock list annotation(s): $seq")
+ def execute(state: CircuitState): CircuitState = {
+ val annos = state.annotations.collect { case a: ClockListAnnotation => a }
+ annos match {
+ case Seq(ClockListAnnotation(ModuleName(top, CircuitName(state.circuit.main)), out)) =>
+ val outputFile = new PrintWriter(out)
+ val newC = (new ClockList(top, outputFile)).run(state.circuit)
+ outputFile.close()
+ CircuitState(newC, state.form, state.annotations)
+ case Nil => state
+ case seq => error(s"Found illegal clock list annotation(s): $seq")
+ }
}
}
diff --git a/src/main/scala/firrtl/passes/memlib/DecorateMems.scala b/src/main/scala/firrtl/passes/memlib/DecorateMems.scala
index ad3616ad..c5302a38 100644
--- a/src/main/scala/firrtl/passes/memlib/DecorateMems.scala
+++ b/src/main/scala/firrtl/passes/memlib/DecorateMems.scala
@@ -16,11 +16,11 @@ class CreateMemoryAnnotations(reader: Option[YamlFileReader]) extends Transform
import CustomYAMLProtocol._
val configs = r.parse[Config]
val cN = CircuitName(state.circuit.main)
- val oldAnnos = state.annotations.getOrElse(AnnotationMap(Seq.empty)).annotations
+ val oldAnnos = state.annotations
val (as, pins) = configs.foldLeft((oldAnnos, Seq.empty[String])) { case ((annos, pins), config) =>
val source = SourceAnnotation(ComponentName(config.source.name, ModuleName(config.source.module, cN)), config.pin.name)
(annos, pins :+ config.pin.name)
}
- state.copy(annotations = Some(AnnotationMap(as :+ PinAnnotation(cN, pins.toSeq))))
+ state.copy(annotations = PinAnnotation(pins.toSeq) +: as)
}
}
diff --git a/src/main/scala/firrtl/passes/memlib/InferReadWrite.scala b/src/main/scala/firrtl/passes/memlib/InferReadWrite.scala
index 73fec1ee..661d6df4 100644
--- a/src/main/scala/firrtl/passes/memlib/InferReadWrite.scala
+++ b/src/main/scala/firrtl/passes/memlib/InferReadWrite.scala
@@ -13,15 +13,7 @@ import firrtl.passes.memlib.AnalysisUtils.{Connects, getConnects, getOrigin}
import WrappedExpression.weq
import annotations._
-object InferReadWriteAnnotation {
- def apply(t: String) = Annotation(CircuitName(t), classOf[InferReadWrite], "")
- def apply(target: CircuitName) = Annotation(target, classOf[InferReadWrite], "")
- def unapply(a: Annotation): Option[(CircuitName)] = a match {
- case Annotation(CircuitName(t), transform, "") if transform == classOf[InferReadWrite] =>
- Some(CircuitName(t))
- case _ => None
- }
-}
+case object InferReadWriteAnnotation extends NoTargetAnnotation
// This pass examine the enable signals of the read & write ports of memories
// whose readLatency is greater than 1 (usually SeqMem in Chisel).
@@ -159,10 +151,13 @@ class InferReadWrite extends Transform with SeqTransformBased {
ResolveKinds,
ResolveGenders
)
- def execute(state: CircuitState): CircuitState = getMyAnnotations(state) match {
- case Nil => state
- case Seq(InferReadWriteAnnotation(CircuitName(state.circuit.main))) =>
+ def execute(state: CircuitState): CircuitState = {
+ val runTransform = state.annotations.contains(InferReadWriteAnnotation)
+ if (runTransform) {
val ret = runTransforms(state)
CircuitState(ret.circuit, outputForm, ret.annotations, ret.renames)
+ } else {
+ state
+ }
}
}
diff --git a/src/main/scala/firrtl/passes/memlib/ReplaceMemMacros.scala b/src/main/scala/firrtl/passes/memlib/ReplaceMemMacros.scala
index bf0612ac..5ac9e63e 100644
--- a/src/main/scala/firrtl/passes/memlib/ReplaceMemMacros.scala
+++ b/src/main/scala/firrtl/passes/memlib/ReplaceMemMacros.scala
@@ -14,19 +14,8 @@ import firrtl.annotations._
import wiring._
-/** Annotates the name of the pin to add for WiringTransform
- */
-object PinAnnotation {
- def apply(target: CircuitName, pins: Seq[String]): Annotation = {
- Annotation(target, classOf[ReplaceMemMacros], s"pins:${pins.mkString(" ")}")
- }
- private val matcher = "pins:(.*)".r
- def unapply(a: Annotation): Option[(CircuitName, Seq[String])] = a match {
- case Annotation(CircuitName(c), _, matcher(rest)) =>
- Some((CircuitName(c), rest.split(" ")))
- case _ => None
- }
-}
+/** Annotates the name of the pins to add for WiringTransform */
+case class PinAnnotation(pins: Seq[String]) extends NoTargetAnnotation
/** Replace DefAnnotatedMemory with memory blackbox + wrapper + conf file.
* This will not generate wmask ports if not needed.
@@ -221,19 +210,17 @@ class ReplaceMemMacros(writer: ConfWriter) extends Transform {
val modules = c.modules map updateMemMods(namespace, nameMap, memMods)
// print conf
writer.serialize()
- val pins = getMyAnnotations(state) match {
- case Nil => Nil
- case Seq(PinAnnotation(CircuitName(c), pins)) => pins
+ val pannos = state.annotations.collect { case a: PinAnnotation => a }
+ val pins = pannos match {
+ case Seq() => Nil
+ case Seq(PinAnnotation(pins)) => pins
case _ => throwInternalError(Some(s"execute: getMyAnnotations - ${getMyAnnotations(state)}"))
}
- val annos = (pins.foldLeft(Seq[Annotation]()) { (seq, pin) =>
- seq ++ memMods.collect {
- case m: ExtModule => SinkAnnotation(ModuleName(m.name, CircuitName(c.main)), pin)
+ val annos = pins.foldLeft(Seq[Annotation]()) { (seq, pin) =>
+ seq ++ memMods.collect {
+ case m: ExtModule => SinkAnnotation(ModuleName(m.name, CircuitName(c.main)), pin)
}
- }) ++ (state.annotations match {
- case None => Seq.empty
- case Some(a) => a.annotations
- })
- CircuitState(c.copy(modules = modules ++ memMods), inputForm, Some(AnnotationMap(annos)))
+ } ++ state.annotations
+ CircuitState(c.copy(modules = modules ++ memMods), inputForm, annos)
}
}
diff --git a/src/main/scala/firrtl/passes/memlib/ReplaceMemTransform.scala b/src/main/scala/firrtl/passes/memlib/ReplaceMemTransform.scala
index 8cbf9da7..311813db 100644
--- a/src/main/scala/firrtl/passes/memlib/ReplaceMemTransform.scala
+++ b/src/main/scala/firrtl/passes/memlib/ReplaceMemTransform.scala
@@ -64,13 +64,15 @@ class ConfWriter(filename: String) {
}
}
+case class ReplSeqMemAnnotation(inputFileName: String, outputConfig: String) extends NoTargetAnnotation
+
object ReplSeqMemAnnotation {
- def apply(t: String): Annotation = {
+ def parse(t: String): ReplSeqMemAnnotation = {
val usage = """
[Optional] ReplSeqMem
Pass to replace sequential memories with blackboxes + configuration file
-Usage:
+Usage:
--replSeqMem -c:<circuit>:-i:<filename>:-o:<filename>
*** Note: sub-arguments to --replSeqMem should be delimited by : and not white space!
@@ -80,30 +82,15 @@ Required Arguments:
Optional Arguments:
-i<filename> Specify the input configuration file (for additional optimizations)
-"""
+"""
val passOptions = PassConfigUtil.getPassOptions(t, usage)
val outputConfig = passOptions.getOrElse(
- OutputConfigFileName,
+ OutputConfigFileName,
error("No output config file provided for ReplSeqMem!" + usage)
)
val inputFileName = PassConfigUtil.getPassOptions(t).getOrElse(InputConfigFileName, "")
- val passCircuit = passOptions.getOrElse(
- PassCircuitName,
- error("No circuit name specified for ReplSeqMem!" + usage)
- )
- val target = CircuitName(passCircuit)
- Annotation(target, classOf[ReplSeqMem], s"$inputFileName $outputConfig")
- }
-
- def apply(target: CircuitName, inputFileName: String, outputConfig: String): Annotation =
- Annotation(target, classOf[ReplSeqMem], s"$inputFileName $outputConfig")
-
- private val matcher = "([^ ]*) ([^ ]+)".r
- def unapply(a: Annotation): Option[(CircuitName, String, String)] = a match {
- case Annotation(CircuitName(c), t, matcher(inputFileName, outputConfig)) if t == classOf[ReplSeqMem] =>
- Some((CircuitName(c), inputFileName, outputConfig))
- case _ => None
+ ReplSeqMemAnnotation(inputFileName, outputConfig)
}
}
@@ -135,12 +122,13 @@ class ReplSeqMem extends Transform {
new SimpleMidTransform(ResolveKinds),
new SimpleMidTransform(ResolveGenders))
- def execute(state: CircuitState): CircuitState = getMyAnnotations(state) match {
- case Nil => state // Do nothing if there are no annotations
- case p => (p.collectFirst { case a if (a.target == CircuitName(state.circuit.main)) => a }) match {
- case Some(ReplSeqMemAnnotation(target, inputFileName, outputConfig)) =>
+ def execute(state: CircuitState): CircuitState = {
+ val annos = state.annotations.collect { case a: ReplSeqMemAnnotation => a }
+ annos match {
+ case Nil => state // Do nothing if there are no annotations
+ case Seq(ReplSeqMemAnnotation(inputFileName, outputConfig)) =>
val inConfigFile = {
- if (inputFileName.isEmpty) None
+ if (inputFileName.isEmpty) None
else if (new File(inputFileName).exists) Some(new YamlFileReader(inputFileName))
else error("Input configuration file does not exist!")
}
diff --git a/src/main/scala/firrtl/passes/memlib/ResolveMemoryReference.scala b/src/main/scala/firrtl/passes/memlib/ResolveMemoryReference.scala
index e132e369..d195ea55 100644
--- a/src/main/scala/firrtl/passes/memlib/ResolveMemoryReference.scala
+++ b/src/main/scala/firrtl/passes/memlib/ResolveMemoryReference.scala
@@ -8,15 +8,9 @@ import AnalysisUtils.eqMems
import firrtl.Mappers._
import firrtl.annotations._
-/** A component, e.g. register etc. Must be declared only once under the TopAnnotation
- */
-object NoDedupMemAnnotation {
- def apply(target: ComponentName): Annotation = Annotation(target, classOf[ResolveMemoryReference], s"nodedupmem!")
-
- def unapply(a: Annotation): Option[ComponentName] = a match {
- case Annotation(ComponentName(n, mn), _, "nodedupmem!") => Some(ComponentName(n, mn))
- case _ => None
- }
+/** A component, e.g. register etc. Must be declared only once under the TopAnnotation */
+case class NoDedupMemAnnotation(target: ComponentName) extends SingleTargetAnnotation[ComponentName] {
+ def duplicate(n: ComponentName) = NoDedupMemAnnotation(n)
}
/** Resolves annotation ref to memories that exactly match (except name) another memory
@@ -46,10 +40,8 @@ class ResolveMemoryReference extends Transform {
c copy (modules = c.modules map (m => m map updateMemStmts(m.name, uniqueMems, noDeDupeMems)))
}
def execute(state: CircuitState): CircuitState = {
- val noDedups = getMyAnnotations(state) match {
- case Nil => Seq.empty
- case annos =>
- annos.collect { case NoDedupMemAnnotation(ComponentName(cn, _)) => cn }
+ val noDedups = state.annotations.collect {
+ case NoDedupMemAnnotation(ComponentName(cn, _)) => cn
}
state.copy(circuit=run(state.circuit, noDedups))
}
diff --git a/src/main/scala/firrtl/passes/wiring/WiringTransform.scala b/src/main/scala/firrtl/passes/wiring/WiringTransform.scala
index 01e6f83a..9a82f8a0 100644
--- a/src/main/scala/firrtl/passes/wiring/WiringTransform.scala
+++ b/src/main/scala/firrtl/passes/wiring/WiringTransform.scala
@@ -14,32 +14,16 @@ import WiringUtils._
/** A class for all exceptions originating from firrtl.passes.wiring */
case class WiringException(msg: String) extends PassException(msg)
-/** An extractor of annotated source components */
-object SourceAnnotation {
- def apply(target: ComponentName, pin: String): Annotation =
- Annotation(target, classOf[WiringTransform], s"source $pin")
-
- private val matcher = "source (.+)".r
- def unapply(a: Annotation): Option[(ComponentName, String)] = a match {
- case Annotation(ComponentName(n, m), _, matcher(pin)) =>
- Some((ComponentName(n, m), pin))
- case _ => None
- }
+/** A component, e.g. register etc. Must be declared only once under the TopAnnotation */
+case class SourceAnnotation(target: ComponentName, pin: String) extends
+ SingleTargetAnnotation[ComponentName] {
+ def duplicate(n: ComponentName) = this.copy(target = n)
}
-/** An extractor of annotation sink components or modules */
-object SinkAnnotation {
- def apply(target: Named, pin: String): Annotation =
- Annotation(target, classOf[WiringTransform], s"sink $pin")
-
- private val matcher = "sink (.+)".r
- def unapply(a: Annotation): Option[(Named, String)] = a match {
- case Annotation(ModuleName(n, c), _, matcher(pin)) =>
- Some((ModuleName(n, c), pin))
- case Annotation(ComponentName(n, m), _, matcher(pin)) =>
- Some((ComponentName(n, m), pin))
- case _ => None
- }
+/** A module, e.g. ExtModule etc., that should add the input pin */
+case class SinkAnnotation(target: Named, pin: String) extends
+ SingleTargetAnnotation[Named] {
+ def duplicate(n: Named) = this.copy(target = n)
}
/** Wires a Module's Source Component to one or more Sink
@@ -64,26 +48,30 @@ class WiringTransform extends Transform {
new Wiring(w),
ToWorkingIR
)
-
- def execute(state: CircuitState): CircuitState = getMyAnnotations(state) match {
- case Nil => state
- case p =>
- val sinks = mutable.HashMap[String, Seq[Named]]()
- val sources = mutable.HashMap[String, ComponentName]()
- p.foreach {
- case SinkAnnotation(m, pin) =>
- sinks(pin) = sinks.getOrElse(pin, Seq.empty) :+ m
- case SourceAnnotation(c, pin) =>
- sources(pin) = c
- }
- (sources.size, sinks.size) match {
- case (0, p) => state
- case (s, p) if (p > 0) =>
- val wis = sources.foldLeft(Seq[WiringInfo]()) { case (seq, (pin, source)) =>
- seq :+ WiringInfo(source, sinks(pin), pin)
- }
- transforms(wis).foldLeft(state) { (in, xform) => xform.runTransform(in) }
- case _ => error("Wrong number of sources or sinks!")
- }
+ def execute(state: CircuitState): CircuitState = {
+ val annos = state.annotations.collect {
+ case a @ (_: SinkAnnotation | _: SourceAnnotation) => a
+ }
+ annos match {
+ case Seq() => state
+ case p =>
+ val sinks = mutable.HashMap[String, Seq[Named]]()
+ val sources = mutable.HashMap[String, ComponentName]()
+ p.foreach {
+ case SinkAnnotation(m, pin) =>
+ sinks(pin) = sinks.getOrElse(pin, Seq.empty) :+ m
+ case SourceAnnotation(c, pin) =>
+ sources(pin) = c
+ }
+ (sources.size, sinks.size) match {
+ case (0, p) => state
+ case (s, p) if (p > 0) =>
+ val wis = sources.foldLeft(Seq[WiringInfo]()) { case (seq, (pin, source)) =>
+ seq :+ WiringInfo(source, sinks(pin), pin)
+ }
+ transforms(wis).foldLeft(state) { (in, xform) => xform.runTransform(in) }
+ case _ => error("Wrong number of sources or sinks!")
+ }
+ }
}
}
diff --git a/src/main/scala/firrtl/transforms/BlackBoxSourceHelper.scala b/src/main/scala/firrtl/transforms/BlackBoxSourceHelper.scala
index 80a8df55..aed9b1f8 100644
--- a/src/main/scala/firrtl/transforms/BlackBoxSourceHelper.scala
+++ b/src/main/scala/firrtl/transforms/BlackBoxSourceHelper.scala
@@ -5,89 +5,59 @@ package firrtl.transforms
import java.io.{File, FileNotFoundException, FileOutputStream, PrintWriter}
import firrtl._
-import firrtl.annotations.{Annotation, ModuleName}
+import firrtl.Utils.throwInternalError
+import firrtl.annotations._
import scala.collection.mutable.ArrayBuffer
+sealed trait BlackBoxHelperAnno extends Annotation
-trait BlackBoxSource {
- def serialize: String
- def name: String
+case class BlackBoxTargetDirAnno(targetDir: String) extends BlackBoxHelperAnno
+ with NoTargetAnnotation {
+ override def serialize: String = s"targetDir\n$targetDir"
}
-object BlackBoxSource {
- val MaxFields = 3
-
- def parse(s: String): Option[BlackBoxSource] = {
- s.split("\n", MaxFields).toList match {
- case "resource" :: id :: _ => Some(BlackBoxResource(id))
- case "inline" :: name :: text :: _ => Some(BlackBoxInline(name, text))
- case "targetDir" :: targetDir :: _ => Some(BlackBoxTargetDir(targetDir))
- case _ => throw new FIRRTLException(s"Error: Bad BlackBox annotations $s")
- }
- }
-}
-
-case class BlackBoxTargetDir(targetDir: String) extends BlackBoxSource {
- def serialize: String = s"targetDir\n$targetDir"
- def name: String = targetDir
-}
-
-case class BlackBoxResource(resourceId: String) extends BlackBoxSource {
- def serialize: String = s"resource\n$resourceId"
- def name: String = resourceId.split("/").last
-}
-
-case class BlackBoxInline(name: String, text: String) extends BlackBoxSource {
- def serialize: String = s"inline\n$name\n$text"
+case class BlackBoxResourceAnno(target: ModuleName, resourceId: String) extends BlackBoxHelperAnno
+ with SingleTargetAnnotation[ModuleName] {
+ def duplicate(n: ModuleName) = this.copy(target = n)
+ override def serialize: String = s"resource\n$resourceId"
}
-object BlackBoxSourceAnnotation {
- def apply(targetDir: ModuleName, value: String): Annotation = {
- assert(BlackBoxSource.parse(value).isDefined)
- Annotation(targetDir, classOf[BlackBoxSourceHelper], value)
- }
-
- def unapply(a: Annotation): Option[(ModuleName, BlackBoxSource)] = a match {
- case Annotation(ModuleName(n, c), _, text) => Some((ModuleName(n, c), BlackBoxSource.parse(text).get))
- case _ => None
- }
+case class BlackBoxInlineAnno(target: ModuleName, name: String, text: String) extends BlackBoxHelperAnno
+ with SingleTargetAnnotation[ModuleName] {
+ def duplicate(n: ModuleName) = this.copy(target = n)
+ override def serialize: String = s"inline\n$name\n$text"
}
-/**
- * This transform handles the moving of verilator source for black boxes into the
+/** Handle source for Verilog ExtModules (BlackBoxes)
+ *
+ * This transform handles the moving of Verilog source for black boxes into the
* target directory so that it can be accessed by verilator or other backend compilers
* While parsing it's annotations it looks for a BlackBoxTargetDir annotation that
- * will set the directory where the verilog will be written. This annotation is typically be
+ * will set the directory where the Verilog will be written. This annotation is typically be
* set by the execution harness, or directly in the tests
*/
class BlackBoxSourceHelper extends firrtl.Transform {
- private var targetDir: File = new File(".")
- private val fileList = new ArrayBuffer[String]
+ private val DefaultTargetDir = new File(".")
override def inputForm: CircuitForm = LowForm
override def outputForm: CircuitForm = LowForm
- /**
- * parse the annotations and convert the generic annotations to specific information
- * required to find the verilog
- * @note Side effect is that while converting a magic target dir annotation is found and sets the target
+ /** Collect BlackBoxHelperAnnos and and find the target dir if specified
* @param annos a list of generic annotations for this transform
- * @return
+ * @return BlackBoxHelperAnnos and target directory
*/
- def getSources(annos: Seq[Annotation]): Seq[BlackBoxSource] = {
- annos.flatMap { anno => BlackBoxSource.parse(anno.value) }
- .flatMap {
- case BlackBoxTargetDir(dest) =>
- targetDir = new File(dest)
- if(! targetDir.exists()) { FileUtils.makeDirectory(targetDir.getAbsolutePath) }
- None
- case b: BlackBoxSource => Some(b)
- case _ => None
+ def collectAnnos(annos: Seq[Annotation]): (Set[BlackBoxHelperAnno], File) =
+ annos.foldLeft((Set.empty[BlackBoxHelperAnno], DefaultTargetDir)) {
+ case ((acc, tdir), anno) => anno match {
+ case BlackBoxTargetDirAnno(dir) =>
+ val targetDir = new File(dir)
+ if (!targetDir.exists()) { FileUtils.makeDirectory(targetDir.getAbsolutePath) }
+ (acc, targetDir)
+ case a: BlackBoxHelperAnno => (acc + a, tdir)
+ case _ => (acc, tdir)
}
- .sortBy(a => a.name)
- .distinct
- }
+ }
/**
* write the verilog source for each annotation to the target directory
@@ -96,31 +66,28 @@ class BlackBoxSourceHelper extends firrtl.Transform {
* @return A transformed Firrtl AST
*/
override def execute(state: CircuitState): CircuitState = {
- val resultState = getMyAnnotations(state) match {
- case Nil => state
- case myAnnotations =>
- val sources = getSources(myAnnotations)
- sources.foreach {
- case BlackBoxResource(resourceId) =>
- val name = resourceId.split("/").last
- val outFile = new File(targetDir, name)
- BlackBoxSourceHelper.copyResourceToFile(resourceId,outFile)
- fileList += outFile.getAbsolutePath
- case BlackBoxInline(name, text) =>
- val outFile = new File(targetDir, name)
- val writer = new PrintWriter(outFile)
- writer.write(text)
- writer.close()
- fileList += outFile.getAbsolutePath
- case _ =>
- }
- state
+ val (annos, targetDir) = collectAnnos(state.annotations)
+ val fileList = annos.foldLeft(List.empty[String]) {
+ case (fileList, anno) => anno match {
+ case BlackBoxResourceAnno(_, resourceId) =>
+ val name = resourceId.split("/").last
+ val outFile = new File(targetDir, name)
+ BlackBoxSourceHelper.copyResourceToFile(resourceId,outFile)
+ outFile.getAbsolutePath +: fileList
+ case BlackBoxInlineAnno(_, name, text) =>
+ val outFile = new File(targetDir, name)
+ val writer = new PrintWriter(outFile)
+ writer.write(text)
+ writer.close()
+ outFile.getAbsolutePath +: fileList
+ case _ => throwInternalError()
+ }
}
// If we have BlackBoxes, generate the helper file.
// If we don't, make sure it doesn't exist or we'll confuse downstream processing
// that triggers behavior on the existence of the file
val helperFile = new File(targetDir, BlackBoxSourceHelper.FileListName)
- if(fileList.nonEmpty) {
+ if (fileList.nonEmpty) {
val writer = new PrintWriter(helperFile)
writer.write(fileList.map { fileName => s"-v $fileName" }.mkString("\n"))
writer.close()
@@ -128,7 +95,7 @@ class BlackBoxSourceHelper extends firrtl.Transform {
helperFile.delete()
}
- resultState
+ state
}
}
diff --git a/src/main/scala/firrtl/transforms/CheckCombLoops.scala b/src/main/scala/firrtl/transforms/CheckCombLoops.scala
index 98d6c3d1..6bd62cfa 100644
--- a/src/main/scala/firrtl/transforms/CheckCombLoops.scala
+++ b/src/main/scala/firrtl/transforms/CheckCombLoops.scala
@@ -22,15 +22,7 @@ object CheckCombLoops {
}
-object DontCheckCombLoopsAnnotation {
- private val marker = "DontCheckCombLoops!"
- private val transform = classOf[CheckCombLoops]
- def apply(): Annotation = Annotation(CircuitTopName, transform, marker)
- def unapply(a: Annotation): Boolean = a match {
- case Annotation(_, targetXform, value) if targetXform == transform && value == marker => true
- case _ => false
- }
-}
+case object DontCheckCombLoopsAnnotation extends NoTargetAnnotation
/** Finds and detects combinational logic loops in a circuit, if any
* exist. Returns the input circuit with no modifications.
@@ -220,9 +212,7 @@ class CheckCombLoops extends Transform {
}
def execute(state: CircuitState): CircuitState = {
- val dontRun = getMyAnnotations(state).collectFirst {
- case DontCheckCombLoopsAnnotation() => true
- }.getOrElse(false)
+ val dontRun = state.annotations.contains(DontCheckCombLoopsAnnotation)
if (dontRun) {
logger.warn("Skipping Combinational Loop Detection")
state
diff --git a/src/main/scala/firrtl/transforms/ConstantPropagation.scala b/src/main/scala/firrtl/transforms/ConstantPropagation.scala
index 04ad2cb2..57b88890 100644
--- a/src/main/scala/firrtl/transforms/ConstantPropagation.scala
+++ b/src/main/scala/firrtl/transforms/ConstantPropagation.scala
@@ -485,11 +485,8 @@ class ConstantPropagation extends Transform {
}
def execute(state: CircuitState): CircuitState = {
- val dontTouches: Seq[(String, String)] = state.annotations match {
- case Some(aMap) => aMap.annotations.collect {
- case DontTouchAnnotation(ComponentName(c, ModuleName(m, _))) => m -> c
- }
- case None => Seq.empty
+ val dontTouches: Seq[(String, String)] = state.annotations.collect {
+ case DontTouchAnnotation(ComponentName(c, ModuleName(m, _))) => m -> c
}
// Map from module name to component names
val dontTouchMap: Map[String, Set[String]] =
diff --git a/src/main/scala/firrtl/transforms/DeadCodeElimination.scala b/src/main/scala/firrtl/transforms/DeadCodeElimination.scala
index 054705c0..8b6b5c85 100644
--- a/src/main/scala/firrtl/transforms/DeadCodeElimination.scala
+++ b/src/main/scala/firrtl/transforms/DeadCodeElimination.scala
@@ -320,23 +320,14 @@ class DeadCodeElimination extends Transform {
}
def execute(state: CircuitState): CircuitState = {
- val (dontTouches: Seq[LogicNode], doTouchExtMods: Seq[String], noDCE: Option[Boolean]) =
- state.annotations match {
- case Some(aMap) =>
- // TODO Do with single walk over annotations
- val dontTouches = aMap.annotations.collect {
- case DontTouchAnnotation(component) => LogicNode(component)
- }
- val optExtMods = aMap.annotations.collect {
- case OptimizableExtModuleAnnotation(ModuleName(name, _)) => name
- }
- val noDCE = aMap.annotations.collectFirst {
- case NoDCEAnnotation() => true
- }
- (dontTouches, optExtMods, noDCE)
- case None => (Seq.empty, Seq.empty, None)
- }
- if (noDCE.getOrElse(false)) {
+ val dontTouches: Seq[LogicNode] = state.annotations.collect {
+ case DontTouchAnnotation(component) => LogicNode(component)
+ }
+ val doTouchExtMods: Seq[String] = state.annotations.collect {
+ case OptimizableExtModuleAnnotation(ModuleName(name, _)) => name
+ }
+ val noDCE = state.annotations.contains(NoDCEAnnotation)
+ if (noDCE) {
logger.info("Skipping DCE")
state
} else {
diff --git a/src/main/scala/firrtl/transforms/Dedup.scala b/src/main/scala/firrtl/transforms/Dedup.scala
index 717481b9..f22415f0 100644
--- a/src/main/scala/firrtl/transforms/Dedup.scala
+++ b/src/main/scala/firrtl/transforms/Dedup.scala
@@ -14,16 +14,10 @@ import scala.collection.mutable
/** A component, e.g. register etc. Must be declared only once under the TopAnnotation
*/
-object NoDedupAnnotation {
- def apply(target: ModuleName): Annotation = Annotation(target, classOf[DedupModules], s"nodedup!")
-
- def unapply(a: Annotation): Option[ModuleName] = a match {
- case Annotation(ModuleName(n, c), _, "nodedup!") => Some(ModuleName(n, c))
- case _ => None
- }
+case class NoDedupAnnotation(target: ModuleName) extends SingleTargetAnnotation[ModuleName] {
+ def duplicate(n: ModuleName) = NoDedupAnnotation(n)
}
-
// Only use on legal Firrtl. Specifically, the restriction of
// instance loops must have been checked, or else this pass can
// infinitely recurse
@@ -150,7 +144,7 @@ class DedupModules extends Transform {
}
def execute(state: CircuitState): CircuitState = {
- val noDedups = getMyAnnotations(state).collect { case NoDedupAnnotation(ModuleName(m, c)) => m }
+ val noDedups = state.annotations.collect { case NoDedupAnnotation(ModuleName(m, c)) => m }
val (newC, renameMap) = run(state.circuit, noDedups)
state.copy(circuit = newC, renames = Some(renameMap))
}
diff --git a/src/main/scala/firrtl/transforms/Flatten.scala b/src/main/scala/firrtl/transforms/Flatten.scala
index cc40c569..6654667a 100644
--- a/src/main/scala/firrtl/transforms/Flatten.scala
+++ b/src/main/scala/firrtl/transforms/Flatten.scala
@@ -10,13 +10,8 @@ import scala.collection.mutable
import firrtl.passes.{InlineInstances,PassException}
/** Tags an annotation to be consumed by this transform */
-object FlattenAnnotation {
- def apply(target: Named): Annotation = Annotation(target, classOf[Flatten], "")
-
- def unapply(a: Annotation): Option[Named] = a match {
- case Annotation(named, t, _) if t == classOf[Flatten] => Some(named)
- case _ => None
- }
+case class FlattenAnnotation(target: Named) extends SingleTargetAnnotation[Named] {
+ def duplicate(n: Named) = FlattenAnnotation(n)
}
/**
@@ -39,7 +34,7 @@ class Flatten extends Transform {
}.toSet, instNames)
case FlattenAnnotation(ModuleName(mod, cir)) => (modNames + ModuleName(mod, cir), instNames)
case FlattenAnnotation(ComponentName(com, mod)) => (modNames, instNames + ComponentName(com, mod))
- case _ => throw new PassException("Annotation must be InlineDeepAnnotation")
+ case _ => throw new PassException("Annotation must be a FlattenAnnotation")
}
}
@@ -107,7 +102,8 @@ class Flatten extends Transform {
}
override def execute(state: CircuitState): CircuitState = {
- getMyAnnotations(state) match {
+ val annos = state.annotations.collect { case a @ FlattenAnnotation(_) => a }
+ annos match {
case Nil => CircuitState(state.circuit, state.form)
case myAnnotations =>
val c = state.circuit
diff --git a/src/main/scala/firrtl/transforms/OptimizationAnnotations.scala b/src/main/scala/firrtl/transforms/OptimizationAnnotations.scala
index 2336710a..42b45813 100644
--- a/src/main/scala/firrtl/transforms/OptimizationAnnotations.scala
+++ b/src/main/scala/firrtl/transforms/OptimizationAnnotations.scala
@@ -6,29 +6,17 @@ import firrtl.annotations._
import firrtl.passes.PassException
/** Indicate that DCE should not be run */
-object NoDCEAnnotation {
- val marker = "noDCE!"
- val transform = classOf[DeadCodeElimination]
- def apply(): Annotation = Annotation(CircuitTopName, transform, marker)
- def unapply(a: Annotation): Boolean = a match {
- case Annotation(_, targetXform, value) if targetXform == transform && value == marker => true
- case _ => false
- }
-}
+case object NoDCEAnnotation extends NoTargetAnnotation
/** A component that should be preserved
*
* DCE treats the component as a top-level sink of the circuit
*/
-object DontTouchAnnotation {
- private val marker = "DONTtouch!"
- def apply(target: ComponentName): Annotation = Annotation(target, classOf[Transform], marker)
-
- def unapply(a: Annotation): Option[ComponentName] = a match {
- case Annotation(component: ComponentName, _, value) if value == marker => Some(component)
- case _ => None
- }
+case class DontTouchAnnotation(target: ComponentName) extends SingleTargetAnnotation[ComponentName] {
+ def duplicate(n: ComponentName) = this.copy(n)
+}
+object DontTouchAnnotation {
class DontTouchNotFoundException(module: String, component: String) extends PassException(
s"Component marked DONT Touch ($module.$component) not found!\n" +
"Perhaps it is an aggregate type? Currently only leaf components are supported.\n" +
@@ -48,12 +36,7 @@ object DontTouchAnnotation {
*
* @note Unlike [[DontTouchAnnotation]], we don't care if the annotation is deleted
*/
-object OptimizableExtModuleAnnotation {
- private val marker = "optimizableExtModule!"
- def apply(target: ModuleName): Annotation = Annotation(target, classOf[Transform], marker)
-
- def unapply(a: Annotation): Option[ModuleName] = a match {
- case Annotation(component: ModuleName, _, value) if value == marker => Some(component)
- case _ => None
- }
+case class OptimizableExtModuleAnnotation(target: ModuleName) extends
+ SingleTargetAnnotation[ModuleName] {
+ def duplicate(n: ModuleName) = this.copy(n)
}