aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJack Koenig2018-02-27 18:07:11 -0800
committerGitHub2018-02-27 18:07:11 -0800
commitc7eb1570dfb1c7701ea32d1209982a053f3cec1d (patch)
tree3f509b202d82841c5dad5588d1f953a25d389b44 /src
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')
-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
-rw-r--r--src/test/resources/annotations/InvalidLegacyAnnotations.anno26
-rw-r--r--src/test/resources/annotations/LegacyAnnotations.anno50
-rw-r--r--src/test/resources/annotations/SampleAnnotations.anno.json39
-rw-r--r--src/test/scala/firrtlTests/AnnotationTests.scala224
-rw-r--r--src/test/scala/firrtlTests/CInferMDirSpec.scala3
-rw-r--r--src/test/scala/firrtlTests/CheckCombLoopsSpec.scala12
-rw-r--r--src/test/scala/firrtlTests/ChirrtlMemSpec.scala25
-rw-r--r--src/test/scala/firrtlTests/DCETests.scala2
-rw-r--r--src/test/scala/firrtlTests/DriverSpec.scala126
-rw-r--r--src/test/scala/firrtlTests/FirrtlSpec.scala13
-rw-r--r--src/test/scala/firrtlTests/InferReadWriteSpec.scala12
-rw-r--r--src/test/scala/firrtlTests/PassTests.scala4
-rw-r--r--src/test/scala/firrtlTests/ReplSeqMemTests.scala36
-rw-r--r--src/test/scala/firrtlTests/UnitTests.scala2
-rw-r--r--src/test/scala/firrtlTests/WiringTests.scala6
-rw-r--r--src/test/scala/firrtlTests/annotationTests/TargetDirAnnotationSpec.scala8
-rw-r--r--src/test/scala/firrtlTests/fixed/FixedPointMathSpec.scala2
-rw-r--r--src/test/scala/firrtlTests/fixed/RemoveFixedTypeSpec.scala2
-rw-r--r--src/test/scala/firrtlTests/transforms/BlacklBoxSourceHelperSpec.scala33
-rw-r--r--src/test/scala/firrtlTests/transforms/DedupTests.scala2
46 files changed, 923 insertions, 769 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)
}
diff --git a/src/test/resources/annotations/InvalidLegacyAnnotations.anno b/src/test/resources/annotations/InvalidLegacyAnnotations.anno
new file mode 100644
index 00000000..75bb3b96
--- /dev/null
+++ b/src/test/resources/annotations/InvalidLegacyAnnotations.anno
@@ -0,0 +1,26 @@
+- targetString: CircuitTop
+ transformClass: firrtl.VerilogEmitter
+ value: emitCircuit
+- targetString: CircuitTop
+ transformClass: firrtl.VerilogEmitter
+ value: emitAllModules
+- targetString: CircuitTop
+ transformClass: firrtl.Transform
+ value: emittedFirrtlCircuit:0
+- targetString: CircuitTop
+ transformClass: firrtl.Transform
+ value: emittedVerilogCircuit:0
+- targetString: CircuitTop
+ transformClass: firrtl.Transform
+ value: emittedFirrtlModule:0
+- targetString: CircuitTop
+ transformClass: firrtl.Transform
+ value: emittedVerilogModule:0
+- targetString: foo
+ transformClass: firrtl.Transform
+ value: |
+ DELETED by DeadCodeElimination
+ targetString: foo
+ transformClass: firrtl.passes.InlineInstances
+ value: ''
+
diff --git a/src/test/resources/annotations/LegacyAnnotations.anno b/src/test/resources/annotations/LegacyAnnotations.anno
new file mode 100644
index 00000000..395fa56d
--- /dev/null
+++ b/src/test/resources/annotations/LegacyAnnotations.anno
@@ -0,0 +1,50 @@
+- targetString: foo
+ transformClass: firrtl.passes.InlineInstances
+ value: ''
+- targetString: foo.bar
+ transformClass: firrtl.passes.clocklist.ClockListTransform
+ value: output
+- targetString: foo
+ transformClass: firrtl.passes.memlib.InferReadWrite
+ value: ''
+- targetString: foo
+ transformClass: firrtl.passes.memlib.ReplSeqMem
+ value: input output
+- targetString: foo.bar.x
+ transformClass: firrtl.passes.memlib.ResolveMemoryReference
+ value: nodedupmem!
+- targetString: foo.bar
+ transformClass: firrtl.transforms.DedupModules
+ value: nodedup!
+- targetString: foo.bar.x
+ transformClass: firrtl.passes.wiring.WiringTransform
+ value: source pin
+- targetString: foo.bar.x
+ transformClass: firrtl.passes.wiring.WiringTransform
+ value: sink pin
+- targetString: foo.bar
+ transformClass: firrtl.transforms.BlackBoxSourceHelper
+ value: |-
+ resource
+ resource
+- targetString: foo.bar
+ transformClass: firrtl.transforms.BlackBoxSourceHelper
+ value: |-
+ inline
+ name
+ text
+- targetString: foo.bar
+ transformClass: firrtl.transforms.BlackBoxSourceHelper
+ value: |-
+ targetDir
+ targetdir
+- targetString: CircuitTop
+ transformClass: firrtl.transforms.DeadCodeElimination
+ value: noDCE!
+- targetString: foo.bar.x
+ transformClass: firrtl.Transform
+ value: DONTtouch!
+- targetString: foo.bar
+ transformClass: firrtl.Transform
+ value: optimizableExtModule!
+
diff --git a/src/test/resources/annotations/SampleAnnotations.anno.json b/src/test/resources/annotations/SampleAnnotations.anno.json
new file mode 100644
index 00000000..e4d912a2
--- /dev/null
+++ b/src/test/resources/annotations/SampleAnnotations.anno.json
@@ -0,0 +1,39 @@
+[
+ {
+ "class":"firrtl.passes.InlineAnnotation",
+ "target":"Top.Foo"
+ },
+ {
+ "class":"firrtl.passes.InlineAnnotation",
+ "target":"Top.Bar"
+ },
+ {
+ "class":"firrtl.passes.InlineAnnotation",
+ "target":"Top.Foo.x"
+ },
+ {
+ "class":"firrtl.passes.InlineAnnotation",
+ "target":"Top.Foo.y"
+ },
+ {
+ "class":"firrtl.passes.InlineAnnotation",
+ "target":"Top"
+ },
+ {
+ "class":"firrtl.passes.InlineAnnotation",
+ "target":"OtherTop"
+ },
+ {
+ "class":"firrtl.passes.InlineAnnotation",
+ "target":"OtherTop.Foo.x"
+ },
+ {
+ "class":"firrtl.passes.InlineAnnotation",
+ "target":"OtherTop.Bar"
+ },
+ {
+ "class":"firrtl.passes.InlineAnnotation",
+ "target":"OtherTop.Foo.y"
+ }
+]
+
diff --git a/src/test/scala/firrtlTests/AnnotationTests.scala b/src/test/scala/firrtlTests/AnnotationTests.scala
index 7b7e7839..85814713 100644
--- a/src/test/scala/firrtlTests/AnnotationTests.scala
+++ b/src/test/scala/firrtlTests/AnnotationTests.scala
@@ -25,32 +25,22 @@ trait AnnotationSpec extends LowTransformSpec {
// Check if Annotation Exception is thrown
override def failingexecute(input: String, annotations: Seq[Annotation]): Exception = {
intercept[AnnotationException] {
- compile(CircuitState(parse(input), ChirrtlForm, Some(AnnotationMap(annotations))), Seq.empty)
+ compile(CircuitState(parse(input), ChirrtlForm, annotations), Seq.empty)
}
}
def execute(input: String, check: Annotation, annotations: Seq[Annotation]): Unit = {
- val cr = compile(CircuitState(parse(input), ChirrtlForm, Some(AnnotationMap(annotations))), Seq.empty)
- cr.annotations.get.annotations should contain (check)
+ val cr = compile(CircuitState(parse(input), ChirrtlForm, annotations), Seq.empty)
+ cr.annotations.toSeq should contain (check)
}
}
+// Abstract but with lots of tests defined so that we can use the same tests
+// for Legacy and newer Annotations
+abstract class AnnotationTests extends AnnotationSpec with Matchers {
+ def anno(s: String, value: String ="this is a value", mod: String = "Top"): Annotation
+ def manno(mod: String): Annotation
-/**
- * Tests for Annotation Permissibility and Tenacity
- *
- * WARNING(izraelevitz): Not a complete suite of tests, requires the LowerTypes
- * pass and ConstProp pass to correctly populate its RenameMap before Strict, Rigid, Firm,
- * Unstable, Fickle, and Insistent can be tested.
- */
-class AnnotationTests extends AnnotationSpec with Matchers {
- def getAMap(a: Annotation): Option[AnnotationMap] = Some(AnnotationMap(Seq(a)))
- def getAMap(as: Seq[Annotation]): Option[AnnotationMap] = Some(AnnotationMap(as))
- def anno(s: String, value: String ="this is a value", mod: String = "Top"): Annotation =
- Annotation(ComponentName(s, ModuleName(mod, CircuitName("Top"))), classOf[Transform], value)
- def manno(mod: String): Annotation =
- Annotation(ModuleName(mod, CircuitName("Top")), classOf[Transform], "some value")
-
- "Loose and Sticky annotation on a node" should "pass through" in {
+ "Annotation on a node" should "pass through" in {
val input: String =
"""circuit Top :
| module Top :
@@ -61,71 +51,6 @@ class AnnotationTests extends AnnotationSpec with Matchers {
execute(input, ta, Seq(ta))
}
- "Annotations" should "be readable from file" in {
- val annotationStream = getClass.getResourceAsStream("/annotations/SampleAnnotations.anno")
- val annotationsYaml = scala.io.Source.fromInputStream(annotationStream).getLines().mkString("\n").parseYaml
- val annotationArray = annotationsYaml.convertTo[Array[Annotation]]
- annotationArray.length should be (9)
- annotationArray(0).targetString should be ("ModC")
- annotationArray(7).transformClass should be ("firrtl.passes.InlineInstances")
- val expectedValue = "TopOfDiamond\nWith\nSome new lines"
- annotationArray(7).value should be (expectedValue)
- }
-
- "Badly formatted serializations" should "return reasonable error messages" in {
- var badYaml =
- """
- |- transformClass: firrtl.passes.InlineInstances
- | targetString: circuit.module..
- | value: ModC.this params 16 32
- """.stripMargin.parseYaml
-
- var thrown = intercept[Exception] {
- badYaml.convertTo[Array[Annotation]]
- }
- thrown.getMessage should include ("Illegal component name")
-
- badYaml =
- """
- |- transformClass: firrtl.passes.InlineInstances
- | targetString: .circuit.module.component
- | value: ModC.this params 16 32
- """.stripMargin.parseYaml
-
- thrown = intercept[Exception] {
- badYaml.convertTo[Array[Annotation]]
- }
- thrown.getMessage should include ("Illegal circuit name")
- }
-
- "Round tripping annotations through text file" should "preserve annotations" in {
- val annos: Array[Annotation] = Seq(
- InlineAnnotation(CircuitName("fox")),
- InlineAnnotation(ModuleName("dog", CircuitName("bear"))),
- InlineAnnotation(ComponentName("chocolate", ModuleName("like", CircuitName("i")))),
- PinAnnotation(CircuitName("Pinniped"), Seq("sea-lion", "monk-seal"))
- ).toArray
-
- val annoFile = new File("temp-anno")
- val writer = new FileWriter(annoFile)
- writer.write(annos.toYaml.prettyPrint)
- writer.close()
-
- val yaml = io.Source.fromFile(annoFile).getLines().mkString("\n").parseYaml
- annoFile.delete()
-
- val readAnnos = yaml.convertTo[Array[Annotation]]
-
- annos.zip(readAnnos).foreach { case (beforeAnno, afterAnno) =>
- beforeAnno.targetString should be (afterAnno.targetString)
- beforeAnno.target should be (afterAnno.target)
- beforeAnno.transformClass should be (afterAnno.transformClass)
- beforeAnno.transform should be (afterAnno.transform)
-
- beforeAnno should be (afterAnno)
- }
- }
-
"Deleting annotations" should "create a DeletedAnnotation" in {
val compiler = new VerilogCompiler
val input =
@@ -136,12 +61,15 @@ class AnnotationTests extends AnnotationSpec with Matchers {
class DeletingTransform extends Transform {
val inputForm = LowForm
val outputForm = LowForm
- def execute(state: CircuitState) = state.copy(annotations = None)
+ def execute(state: CircuitState) = state.copy(annotations = Seq())
}
+ val transform = new DeletingTransform
+ val tname = transform.name
val inlineAnn = InlineAnnotation(CircuitName("Top"))
- val result = compiler.compile(CircuitState(parse(input), ChirrtlForm, getAMap(inlineAnn)), Seq(new DeletingTransform))
- result.annotations.get.annotations.head should matchPattern {
- case DeletedAnnotation(x, inlineAnn) =>
+ val result = compiler.compile(CircuitState(parse(input), ChirrtlForm, Seq(inlineAnn)), Seq(transform))
+ println(result.annotations.head)
+ result.annotations.head should matchPattern {
+ case DeletedAnnotation(`tname`, `inlineAnn`) =>
}
val exception = (intercept[FIRRTLException] {
result.getEmittedCircuit
@@ -149,6 +77,7 @@ class AnnotationTests extends AnnotationSpec with Matchers {
val deleted = result.deletedAnnotations
exception.str should be (s"No EmittedCircuit found! Did you delete any annotations?\n$deleted")
}
+
"Renaming" should "propagate in Lowering of memories" in {
val compiler = new VerilogCompiler
// Uncomment to help debugging failing tests
@@ -170,8 +99,8 @@ class AnnotationTests extends AnnotationSpec with Matchers {
|""".stripMargin
val annos = Seq(anno("m.r.data.b", "sub"), anno("m.r.data", "all"), anno("m", "mem"),
dontTouch("Top.m"))
- val result = compiler.compile(CircuitState(parse(input), ChirrtlForm, getAMap(annos)), Nil)
- val resultAnno = result.annotations.get.annotations
+ val result = compiler.compile(CircuitState(parse(input), ChirrtlForm, annos), Nil)
+ val resultAnno = result.annotations.toSeq
resultAnno should contain (anno("m_a", "mem"))
resultAnno should contain (anno("m_b_0", "mem"))
resultAnno should contain (anno("m_b_1", "mem"))
@@ -185,7 +114,6 @@ class AnnotationTests extends AnnotationSpec with Matchers {
}
"Renaming" should "propagate in RemoveChirrtl and Lowering of memories" in {
val compiler = new VerilogCompiler
- Logger.setClassLogLevels(Map(compiler.getClass.getName -> LogLevel.Debug))
val input =
"""circuit Top :
| module Top :
@@ -195,8 +123,8 @@ class AnnotationTests extends AnnotationSpec with Matchers {
| read mport r = m[in], clk
|""".stripMargin
val annos = Seq(anno("r.b", "sub"), anno("r", "all"), anno("m", "mem"), dontTouch("Top.m"))
- val result = compiler.compile(CircuitState(parse(input), ChirrtlForm, getAMap(annos)), Nil)
- val resultAnno = result.annotations.get.annotations
+ val result = compiler.compile(CircuitState(parse(input), ChirrtlForm, annos), Nil)
+ val resultAnno = result.annotations.toSeq
resultAnno should contain (anno("m_a", "mem"))
resultAnno should contain (anno("m_b_0", "mem"))
resultAnno should contain (anno("m_b_1", "mem"))
@@ -225,8 +153,8 @@ class AnnotationTests extends AnnotationSpec with Matchers {
|""".stripMargin
val annos = Seq(anno("zero"), anno("x.a"), anno("x.b"), anno("y[0]"), anno("y[1]"),
anno("y[2]"), dontTouch("Top.x"))
- val result = compiler.compile(CircuitState(parse(input), ChirrtlForm, getAMap(annos)), Nil)
- val resultAnno = result.annotations.get.annotations
+ val result = compiler.compile(CircuitState(parse(input), ChirrtlForm, annos), Nil)
+ val resultAnno = result.annotations.toSeq
resultAnno should contain (anno("x_a"))
resultAnno should not contain (anno("zero"))
resultAnno should not contain (anno("x.a"))
@@ -267,8 +195,8 @@ class AnnotationTests extends AnnotationSpec with Matchers {
anno("write.a"), anno("write.b[0]"), anno("write.b[1]"),
dontTouch("Top.r"), dontTouch("Top.w")
)
- val result = compiler.compile(CircuitState(parse(input), ChirrtlForm, getAMap(annos)), Nil)
- val resultAnno = result.annotations.get.annotations
+ val result = compiler.compile(CircuitState(parse(input), ChirrtlForm, annos), Nil)
+ val resultAnno = result.annotations.toSeq
resultAnno should not contain (anno("in.a"))
resultAnno should not contain (anno("in.b[0]"))
resultAnno should not contain (anno("in.b[1]"))
@@ -321,8 +249,8 @@ class AnnotationTests extends AnnotationSpec with Matchers {
|""".stripMargin
val annos = Seq(anno("in"), anno("out"), anno("w"), anno("n"), anno("r"), dontTouch("Top.r"),
dontTouch("Top.w"))
- val result = compiler.compile(CircuitState(parse(input), ChirrtlForm, getAMap(annos)), Nil)
- val resultAnno = result.annotations.get.annotations
+ val result = compiler.compile(CircuitState(parse(input), ChirrtlForm, annos), Nil)
+ val resultAnno = result.annotations.toSeq
resultAnno should contain (anno("in_a"))
resultAnno should contain (anno("in_b_0"))
resultAnno should contain (anno("in_b_1"))
@@ -357,8 +285,8 @@ class AnnotationTests extends AnnotationSpec with Matchers {
|""".stripMargin
val annos = Seq(anno("in.b"), anno("out.b"), anno("w.b"), anno("n.b"), anno("r.b"),
dontTouch("Top.r"), dontTouch("Top.w"))
- val result = compiler.compile(CircuitState(parse(input), ChirrtlForm, getAMap(annos)), Nil)
- val resultAnno = result.annotations.get.annotations
+ val result = compiler.compile(CircuitState(parse(input), ChirrtlForm, annos), Nil)
+ val resultAnno = result.annotations.toSeq
resultAnno should contain (anno("in_b_0"))
resultAnno should contain (anno("in_b_1"))
resultAnno should contain (anno("out_b_0"))
@@ -388,8 +316,8 @@ class AnnotationTests extends AnnotationSpec with Matchers {
anno("out.a"), anno("out.b[0]"), anno("out.b[1]"),
anno("n.a"), anno("n.b[0]"), anno("n.b[1]")
)
- val result = compiler.compile(CircuitState(parse(input), ChirrtlForm, getAMap(annos)), Nil)
- val resultAnno = result.annotations.get.annotations
+ val result = compiler.compile(CircuitState(parse(input), ChirrtlForm, annos), Nil)
+ val resultAnno = result.annotations.toSeq
resultAnno should not contain (anno("in.a"))
resultAnno should not contain (anno("in.b[0]"))
resultAnno should not contain (anno("in.b[1]"))
@@ -438,17 +366,17 @@ class AnnotationTests extends AnnotationSpec with Matchers {
anno("foo", mod = "Dead"), anno("bar", mod = "Dead"),
anno("foo", mod = "DeadExt"), anno("bar", mod = "DeadExt")
)
- val result = compiler.compile(CircuitState(parse(input), ChirrtlForm, getAMap(annos)), Nil)
+ val result = compiler.compile(CircuitState(parse(input), ChirrtlForm, annos), Nil)
/* Uncomment to help debug
println(result.circuit.serialize)
- result.annotations.get.annotations.foreach{ a =>
+ result.annotations.foreach{ a =>
a match {
case DeletedAnnotation(xform, anno) => println(s"$xform deleted: ${a.target}")
case Annotation(target, _, _) => println(s"not deleted: $target")
}
}
*/
- val resultAnno = result.annotations.get.annotations
+ val resultAnno = result.annotations.toSeq
resultAnno should contain (manno("Top"))
resultAnno should contain (anno("foo", mod = "Top"))
@@ -488,8 +416,8 @@ class AnnotationTests extends AnnotationSpec with Matchers {
val annos = Seq(
anno("x", mod = "Child"), anno("y", mod = "Child_1"), manno("Child"), manno("Child_1")
)
- val result = compiler.compile(CircuitState(parse(input), ChirrtlForm, getAMap(annos)), Nil)
- val resultAnno = result.annotations.get.annotations
+ val result = compiler.compile(CircuitState(parse(input), ChirrtlForm, annos), Nil)
+ val resultAnno = result.annotations.toSeq
resultAnno should contain (anno("x", mod = "Child"))
resultAnno should contain (anno("y", mod = "Child"))
resultAnno should contain (manno("Child"))
@@ -503,3 +431,83 @@ class AnnotationTests extends AnnotationSpec with Matchers {
require(x == y)
}
}
+
+class LegacyAnnotationTests extends AnnotationTests {
+ def anno(s: String, value: String ="this is a value", mod: String = "Top"): Annotation =
+ Annotation(ComponentName(s, ModuleName(mod, CircuitName("Top"))), classOf[Transform], value)
+ def manno(mod: String): Annotation =
+ Annotation(ModuleName(mod, CircuitName("Top")), classOf[Transform], "some value")
+
+ "LegacyAnnotations" should "be readable from file" in {
+ val annotationStream = getClass.getResourceAsStream("/annotations/SampleAnnotations.anno")
+ val annotationsYaml = scala.io.Source.fromInputStream(annotationStream).getLines().mkString("\n").parseYaml
+ val annotationArray = annotationsYaml.convertTo[Array[LegacyAnnotation]]
+ annotationArray.length should be (9)
+ annotationArray(0).targetString should be ("ModC")
+ annotationArray(7).transformClass should be ("firrtl.passes.InlineInstances")
+ val expectedValue = "TopOfDiamond\nWith\nSome new lines"
+ annotationArray(7).value should be (expectedValue)
+ }
+
+ "Badly formatted LegacyAnnotation serializations" should "return reasonable error messages" in {
+ var badYaml =
+ """
+ |- transformClass: firrtl.passes.InlineInstances
+ | targetString: circuit.module..
+ | value: ModC.this params 16 32
+ """.stripMargin.parseYaml
+
+ var thrown = intercept[Exception] {
+ badYaml.convertTo[Array[LegacyAnnotation]]
+ }
+ thrown.getMessage should include ("Illegal component name")
+
+ badYaml =
+ """
+ |- transformClass: firrtl.passes.InlineInstances
+ | targetString: .circuit.module.component
+ | value: ModC.this params 16 32
+ """.stripMargin.parseYaml
+
+ thrown = intercept[Exception] {
+ badYaml.convertTo[Array[LegacyAnnotation]]
+ }
+ thrown.getMessage should include ("Illegal circuit name")
+ }
+}
+
+class JsonAnnotationTests extends AnnotationTests {
+ // Helper annotations
+ case class SimpleAnno(target: ComponentName, value: String) extends
+ SingleTargetAnnotation[ComponentName] {
+ def duplicate(n: ComponentName) = this.copy(target = n)
+ }
+ case class ModuleAnno(target: ModuleName) extends SingleTargetAnnotation[ModuleName] {
+ def duplicate(n: ModuleName) = this.copy(target = n)
+ }
+
+ def anno(s: String, value: String ="this is a value", mod: String = "Top"): SimpleAnno =
+ SimpleAnno(ComponentName(s, ModuleName(mod, CircuitName("Top"))), value)
+ def manno(mod: String): Annotation = ModuleAnno(ModuleName(mod, CircuitName("Top")))
+
+ "Round tripping annotations through text file" should "preserve annotations" in {
+ val annos: Array[Annotation] = Seq(
+ InlineAnnotation(CircuitName("fox")),
+ InlineAnnotation(ModuleName("dog", CircuitName("bear"))),
+ InlineAnnotation(ComponentName("chocolate", ModuleName("like", CircuitName("i")))),
+ PinAnnotation(Seq("sea-lion", "monk-seal"))
+ ).toArray
+
+ val annoFile = new File("temp-anno")
+ val writer = new FileWriter(annoFile)
+ writer.write(JsonProtocol.serialize(annos))
+ writer.close()
+
+ val text = io.Source.fromFile(annoFile).getLines().mkString("\n")
+ annoFile.delete()
+
+ val readAnnos = JsonProtocol.deserializeTry(text).get
+
+ annos should be (readAnnos)
+ }
+}
diff --git a/src/test/scala/firrtlTests/CInferMDirSpec.scala b/src/test/scala/firrtlTests/CInferMDirSpec.scala
index 299142d9..a0f55794 100644
--- a/src/test/scala/firrtlTests/CInferMDirSpec.scala
+++ b/src/test/scala/firrtlTests/CInferMDirSpec.scala
@@ -68,8 +68,7 @@ circuit foo :
bar <= io.in
""".stripMargin
- val annotationMap = AnnotationMap(Nil)
- val res = compileAndEmit(CircuitState(parse(input), ChirrtlForm, Some(annotationMap)))
+ val res = compileAndEmit(CircuitState(parse(input), ChirrtlForm))
// Check correctness of firrtl
parse(res.getEmittedCircuit.value)
}
diff --git a/src/test/scala/firrtlTests/CheckCombLoopsSpec.scala b/src/test/scala/firrtlTests/CheckCombLoopsSpec.scala
index 6c8a2f20..06cbb8e4 100644
--- a/src/test/scala/firrtlTests/CheckCombLoopsSpec.scala
+++ b/src/test/scala/firrtlTests/CheckCombLoopsSpec.scala
@@ -45,7 +45,7 @@ class CheckCombLoopsSpec extends SimpleTransformSpec {
|""".stripMargin
val writer = new java.io.StringWriter
- compile(CircuitState(parse(input), ChirrtlForm, None), writer)
+ compile(CircuitState(parse(input), ChirrtlForm), writer)
}
"Simple combinational loop" should "throw an exception" in {
@@ -66,7 +66,7 @@ class CheckCombLoopsSpec extends SimpleTransformSpec {
val writer = new java.io.StringWriter
intercept[CheckCombLoops.CombLoopException] {
- compile(CircuitState(parse(input), ChirrtlForm, None), writer)
+ compile(CircuitState(parse(input), ChirrtlForm), writer)
}
}
@@ -87,7 +87,7 @@ class CheckCombLoopsSpec extends SimpleTransformSpec {
val writer = new java.io.StringWriter
intercept[CheckCombLoops.CombLoopException] {
- compile(CircuitState(parse(input), ChirrtlForm, None), writer)
+ compile(CircuitState(parse(input), ChirrtlForm), writer)
}
}
@@ -119,7 +119,7 @@ class CheckCombLoopsSpec extends SimpleTransformSpec {
val writer = new java.io.StringWriter
intercept[CheckCombLoops.CombLoopException] {
- compile(CircuitState(parse(input), ChirrtlForm, None), writer)
+ compile(CircuitState(parse(input), ChirrtlForm), writer)
}
}
@@ -147,7 +147,7 @@ class CheckCombLoopsSpec extends SimpleTransformSpec {
val writer = new java.io.StringWriter
intercept[CheckCombLoops.CombLoopException] {
- compile(CircuitState(parse(input), ChirrtlForm, None), writer)
+ compile(CircuitState(parse(input), ChirrtlForm), writer)
}
}
@@ -171,7 +171,7 @@ class CheckCombLoopsSpec extends SimpleTransformSpec {
val writer = new java.io.StringWriter
intercept[CheckCombLoops.CombLoopException] {
- compile(CircuitState(parse(input), ChirrtlForm, None), writer)
+ compile(CircuitState(parse(input), ChirrtlForm), writer)
}
}
}
diff --git a/src/test/scala/firrtlTests/ChirrtlMemSpec.scala b/src/test/scala/firrtlTests/ChirrtlMemSpec.scala
index d039cc96..74d39286 100644
--- a/src/test/scala/firrtlTests/ChirrtlMemSpec.scala
+++ b/src/test/scala/firrtlTests/ChirrtlMemSpec.scala
@@ -78,8 +78,7 @@ circuit foo :
io.out <= bar
""".stripMargin
- val annotationMap = AnnotationMap(Nil)
- val res = compileAndEmit(CircuitState(parse(input), ChirrtlForm, Some(annotationMap)))
+ val res = compileAndEmit(CircuitState(parse(input), ChirrtlForm))
// Check correctness of firrtl
parse(res.getEmittedCircuit.value)
}
@@ -104,14 +103,13 @@ circuit foo :
io.out <= bar
""".stripMargin
- val annotationMap = AnnotationMap(Nil)
- val res = compileAndEmit(CircuitState(parse(input), ChirrtlForm, Some(annotationMap)))
+ val res = compileAndEmit(CircuitState(parse(input), ChirrtlForm))
// Check correctness of firrtl
parse(res.getEmittedCircuit.value)
}
ignore should "Memories should not have validif on port clocks when declared in a when" in {
- val input =
+ val input =
""";buildInfoPackage: chisel3, version: 3.0-SNAPSHOT, scalaVersion: 2.11.11, sbtVersion: 0.13.16, builtAtString: 2017-10-06 20:55:20.367, builtAtMillis: 1507323320367
|circuit Stack :
| module Stack :
@@ -157,8 +155,7 @@ circuit foo :
| skip @[Stack.scala 19:16]
| io.dataOut <= out @[Stack.scala 31:14]
""".stripMargin
- val annotationMap = AnnotationMap(Nil)
- val res = (new LowFirrtlCompiler).compile(CircuitState(parse(input), ChirrtlForm, Some(annotationMap)), Nil).circuit
+ val res = (new LowFirrtlCompiler).compile(CircuitState(parse(input), ChirrtlForm), Seq()).circuit
assert(res search {
case Connect(_, WSubField(WSubField(WRef("stack_mem", _, _, _), "_T_35",_, _), "clk", _, _), WRef("clock", _, _, _)) => true
case Connect(_, WSubField(WSubField(WRef("stack_mem", _, _, _), "_T_17",_, _), "clk", _, _), WRef("clock", _, _, _)) => true
@@ -179,8 +176,7 @@ circuit foo :
| read mport bar = mem[addr], clock
| out <= bar
|""".stripMargin
- val annotationMap = AnnotationMap(Nil)
- val res = (new LowFirrtlCompiler).compile(CircuitState(parse(input), ChirrtlForm, Some(annotationMap)), Nil).circuit
+ val res = (new LowFirrtlCompiler).compile(CircuitState(parse(input), ChirrtlForm), Seq()).circuit
assert(res search {
case Connect(_, WSubField(WSubField(WRef("mem", _, _, _), "bar",_, _), "clk", _, _), WRef("clock", _, _, _)) => true
})
@@ -201,8 +197,7 @@ circuit foo :
| read mport bar = mem[addr], local
| out <= bar
|""".stripMargin
- val annotationMap = AnnotationMap(Nil)
- val res = new LowFirrtlCompiler().compile(CircuitState(parse(input), ChirrtlForm, Some(annotationMap)), Nil).circuit
+ val res = new LowFirrtlCompiler().compile(CircuitState(parse(input), ChirrtlForm), Seq()).circuit
assert(res search {
case Connect(_, WSubField(WSubField(WRef("mem", _, _, _), "bar",_, _), "clk", _, _), WRef("clock", _, _, _)) => true
})
@@ -223,9 +218,7 @@ circuit foo :
| read mport bar = mem[addr], asClock(local)
| out <= bar
|""".stripMargin
- val annotationMap = AnnotationMap(Nil)
-
- val res = new LowFirrtlCompiler().compile(CircuitState(parse(input), ChirrtlForm, Some(annotationMap)), Nil).circuit
+ val res = new LowFirrtlCompiler().compile(CircuitState(parse(input), ChirrtlForm), Seq()).circuit
assert(res search {
case Connect(_, WSubField(WSubField(WRef("mem", _, _, _), "bar",_, _), "clk", _, _), DoPrim(AsClock, Seq(WRef("clock", _, _, _)), Nil, _)) => true
})
@@ -246,9 +239,7 @@ circuit foo :
| read mport bar = mem[addr], asClock(clock)
| out <= bar
|""".stripMargin
- val annotationMap = AnnotationMap(Nil)
-
- val res = (new HighFirrtlCompiler).compile(CircuitState(parse(input), ChirrtlForm, Some(annotationMap)), Nil).circuit
+ val res = (new HighFirrtlCompiler).compile(CircuitState(parse(input), ChirrtlForm), Seq()).circuit
assert(res search {
case Connect(_, SubField(SubField(Reference("mem", _), "bar", _), "clk", _), DoPrim(AsClock, Seq(Reference("clock", _)), _, _)) => true
})
diff --git a/src/test/scala/firrtlTests/DCETests.scala b/src/test/scala/firrtlTests/DCETests.scala
index e28ab432..97c1c146 100644
--- a/src/test/scala/firrtlTests/DCETests.scala
+++ b/src/test/scala/firrtlTests/DCETests.scala
@@ -20,7 +20,7 @@ class DCETests extends FirrtlFlatSpec {
new SimpleTransform(RemoveEmpty, LowForm)
)
private def exec(input: String, check: String, annos: Seq[Annotation] = List.empty): Unit = {
- val state = CircuitState(parse(input), ChirrtlForm, Some(AnnotationMap(annos)))
+ val state = CircuitState(parse(input), ChirrtlForm, annos)
val finalState = (new LowFirrtlCompiler).compileAndEmit(state, customTransforms)
val res = finalState.getEmittedCircuit.value
// Convert to sets for comparison
diff --git a/src/test/scala/firrtlTests/DriverSpec.scala b/src/test/scala/firrtlTests/DriverSpec.scala
index 0327cf8b..406e5f42 100644
--- a/src/test/scala/firrtlTests/DriverSpec.scala
+++ b/src/test/scala/firrtlTests/DriverSpec.scala
@@ -2,15 +2,32 @@
package firrtlTests
-import java.io.File
+import java.io.{File, FileWriter}
import org.scalatest.{FreeSpec, Matchers}
-import firrtl.passes.InlineInstances
-import firrtl.passes.memlib.{InferReadWrite, ReplSeqMem}
-import firrtl.transforms.BlackBoxSourceHelper
+import firrtl.passes.{InlineAnnotation, InlineInstances}
+import firrtl.passes.memlib.{
+ InferReadWrite,
+ InferReadWriteAnnotation,
+ ReplSeqMem,
+ ReplSeqMemAnnotation
+}
+import firrtl.transforms.BlackBoxTargetDirAnno
import firrtl._
+import firrtl.annotations._
import firrtl.util.BackendCompilationUtilities
+class ExceptingTransform extends Transform {
+ def inputForm = HighForm
+ def outputForm = HighForm
+ def execute(state: CircuitState): CircuitState = {
+ throw new ExceptingTransform.CustomException("I ran!")
+ }
+}
+object ExceptingTransform {
+ case class CustomException(msg: String) extends Exception
+}
+
//noinspection ScalaStyle
class DriverSpec extends FreeSpec with Matchers with BackendCompilationUtilities {
"CommonOptions are some simple options available across the chisel3 ecosystem" - {
@@ -117,9 +134,7 @@ class DriverSpec extends FreeSpec with Matchers with BackendCompilationUtilities
val firrtlOptions = optionsManager.firrtlOptions
firrtlOptions.annotations.length should be (3)
- firrtlOptions.annotations.foreach { annotation =>
- annotation.transform shouldBe classOf[InlineInstances]
- }
+ firrtlOptions.annotations.foreach(_ shouldBe an [InlineAnnotation])
}
"infer-rw annotation" in {
val optionsManager = new ExecutionOptionsManager("test") with HasFirrtlOptions
@@ -130,9 +145,7 @@ class DriverSpec extends FreeSpec with Matchers with BackendCompilationUtilities
val firrtlOptions = optionsManager.firrtlOptions
firrtlOptions.annotations.length should be (1)
- firrtlOptions.annotations.foreach { annotation =>
- annotation.transform shouldBe classOf[InferReadWrite]
- }
+ firrtlOptions.annotations.head should be (InferReadWriteAnnotation)
}
"repl-seq-mem annotation" in {
val optionsManager = new ExecutionOptionsManager("test") with HasFirrtlOptions
@@ -143,8 +156,8 @@ class DriverSpec extends FreeSpec with Matchers with BackendCompilationUtilities
val firrtlOptions = optionsManager.firrtlOptions
firrtlOptions.annotations.length should be (1)
- firrtlOptions.annotations.foreach { annotation =>
- annotation.transform shouldBe classOf[ReplSeqMem]
+ firrtlOptions.annotations.head should matchPattern {
+ case ReplSeqMemAnnotation("infile1", "outfile1") =>
}
}
}
@@ -161,7 +174,7 @@ class DriverSpec extends FreeSpec with Matchers with BackendCompilationUtilities
optionsManager.firrtlOptions.annotations.length should be (0)
val annos = Driver.getAnnotations(optionsManager)
annos.length should be (12) // 9 from circuit plus 3 general purpose
- annos.count(_.transformClass == "firrtl.passes.InlineInstances") should be (9)
+ annos.count(_.isInstanceOf[InlineAnnotation]) should be (9)
annoFile.delete()
}
@@ -178,12 +191,83 @@ class DriverSpec extends FreeSpec with Matchers with BackendCompilationUtilities
optionsManager.firrtlOptions.annotations.length should be (0)
val annos = Driver.getAnnotations(optionsManager)
annos.length should be (12) // 9 from circuit plus 3 general purpose
- annos.count(_.transformClass == "firrtl.passes.InlineInstances") should be (9)
+ annos.count(_.isInstanceOf[InlineAnnotation]) should be (9)
annotationsTestFile.delete()
}
+ // Deprecated
+ "Supported LegacyAnnotations will be converted automagically" in {
+ val testDir = createTestDirectory("test")
+ val annoFilename = "LegacyAnnotations.anno"
+ val annotationsTestFile = new File(testDir, annoFilename)
+ val optionsManager = new ExecutionOptionsManager("test") with HasFirrtlOptions {
+ commonOptions = commonOptions.copy(topName = "test", targetDirName = testDir.toString)
+ firrtlOptions = firrtlOptions.copy(
+ annotationFileNames = List(annotationsTestFile.toString)
+ )
+ }
+ copyResourceToFile(s"/annotations/$annoFilename", annotationsTestFile)
+ val annos = Driver.getAnnotations(optionsManager)
+
+ val cname = CircuitName("foo")
+ val mname = ModuleName("bar", cname)
+ val compname = ComponentName("x", mname)
+ import firrtl.passes.clocklist._
+ import firrtl.passes.memlib._
+ import firrtl.passes.wiring._
+ import firrtl.transforms._
+ val expected = List(
+ InlineAnnotation(cname),
+ ClockListAnnotation(mname, "output"),
+ InferReadWriteAnnotation,
+ ReplSeqMemAnnotation("input", "output"),
+ NoDedupMemAnnotation(compname),
+ NoDedupAnnotation(mname),
+ SourceAnnotation(compname, "pin"),
+ SinkAnnotation(compname, "pin"),
+ BlackBoxResourceAnno(mname, "resource"),
+ BlackBoxInlineAnno(mname, "name", "text"),
+ BlackBoxTargetDirAnno("targetdir"),
+ NoDCEAnnotation,
+ DontTouchAnnotation(compname),
+ OptimizableExtModuleAnnotation(mname)
+ )
+ for (e <- expected) {
+ annos should contain (e)
+ }
+ }
+
+ // Deprecated
+ "UNsupported LegacyAnnotations should throw errors" in {
+ val testDir = createTestDirectory("test")
+ val annoFilename = "InvalidLegacyAnnotations.anno"
+ val annotationsTestFile = new File(testDir, annoFilename)
+ copyResourceToFile(s"/annotations/$annoFilename", annotationsTestFile)
+
+ import net.jcazevedo.moultingyaml._
+ val text = io.Source.fromFile(annotationsTestFile).mkString
+ val yamlAnnos = text.parseYaml match { case YamlArray(xs) => xs }
+
+ // Since each one should error, emit each one to an anno file and try to read it
+ for ((anno, i) <- yamlAnnos.zipWithIndex) {
+ val annoFile = new File(testDir, s"anno_$i.anno")
+ val fw = new FileWriter(annoFile)
+ fw.write(YamlArray(anno).prettyPrint)
+ fw.close()
+ val optionsManager = new ExecutionOptionsManager("test") with HasFirrtlOptions {
+ commonOptions = commonOptions.copy(topName = "test", targetDirName = testDir.toString)
+ firrtlOptions = firrtlOptions.copy(
+ annotationFileNames = List(annoFile.toString)
+ )
+ }
+ (the [Exception] thrownBy {
+ Driver.getAnnotations(optionsManager)
+ }).getMessage should include ("Old-style annotations")
+ }
+ }
+
"Annotations can be read from multiple files" in {
- val filename = "SampleAnnotations.anno"
+ val filename = "SampleAnnotations.anno.json"
val optionsManager = new ExecutionOptionsManager("test") with HasFirrtlOptions {
commonOptions = commonOptions.copy(topName = "a.fir")
firrtlOptions = firrtlOptions.copy(
@@ -195,7 +279,7 @@ class DriverSpec extends FreeSpec with Matchers with BackendCompilationUtilities
optionsManager.firrtlOptions.annotations.length should be (0)
val annos = Driver.getAnnotations(optionsManager)
annos.length should be (21) // 18 from files plus 3 general purpose
- annos.count(_.transformClass == "firrtl.passes.InlineInstances") should be (18)
+ annos.count(_.isInstanceOf[InlineAnnotation]) should be (18)
annotationsTestFile.delete()
}
@@ -208,15 +292,15 @@ class DriverSpec extends FreeSpec with Matchers with BackendCompilationUtilities
Array("--infer-rw", "circuit", "-faf", annoFile.toString)
) should be (true)
- copyResourceToFile("/annotations/SampleAnnotations.anno", annoFile)
+ copyResourceToFile("/annotations/SampleAnnotations.anno.json", annoFile)
val firrtlOptions = optionsManager.firrtlOptions
firrtlOptions.annotations.length should be (1) // infer-rw
- val anns = Driver.getAnnotations(optionsManager).groupBy(_.transform)
- anns(classOf[BlackBoxSourceHelper]).length should be (1) // built-in to getAnnotations
- anns(classOf[InferReadWrite]).length should be (1) // --infer-rw
- anns(classOf[InlineInstances]).length should be (9) // annotations file
+ val anns = Driver.getAnnotations(optionsManager)
+ anns should contain (BlackBoxTargetDirAnno(".")) // built in to getAnnotations
+ anns should contain (InferReadWriteAnnotation) // --infer-rw
+ anns.collect { case a: InlineAnnotation => a }.length should be (9) // annotations file
annoFile.delete()
}
diff --git a/src/test/scala/firrtlTests/FirrtlSpec.scala b/src/test/scala/firrtlTests/FirrtlSpec.scala
index b71e51e2..861d1745 100644
--- a/src/test/scala/firrtlTests/FirrtlSpec.scala
+++ b/src/test/scala/firrtlTests/FirrtlSpec.scala
@@ -22,10 +22,10 @@ trait FirrtlRunners extends BackendCompilationUtilities {
val cppHarnessResourceName: String = "/firrtl/testTop.cpp"
/** Compiles input Firrtl to Verilog */
- def compileToVerilog(input: String, annotations: AnnotationMap = AnnotationMap(Seq.empty)): String = {
+ def compileToVerilog(input: String, annotations: AnnotationSeq = Seq.empty): String = {
val circuit = Parser.parse(input.split("\n").toIterator)
val compiler = new VerilogCompiler
- val res = compiler.compileAndEmit(CircuitState(circuit, HighForm, Some(annotations)))
+ val res = compiler.compileAndEmit(CircuitState(circuit, HighForm, annotations))
res.getEmittedCircuit.value
}
/** Compile a Firrtl file
@@ -38,7 +38,7 @@ trait FirrtlRunners extends BackendCompilationUtilities {
prefix: String,
srcDir: String,
customTransforms: Seq[Transform] = Seq.empty,
- annotations: AnnotationMap = new AnnotationMap(Seq.empty)): File = {
+ annotations: AnnotationSeq = Seq.empty): File = {
val testDir = createTestDirectory(prefix)
copyResourceToFile(s"${srcDir}/${prefix}.fir", new File(testDir, s"${prefix}.fir"))
@@ -47,7 +47,7 @@ trait FirrtlRunners extends BackendCompilationUtilities {
firrtlOptions = FirrtlExecutionOptions(
infoModeName = "ignore",
customTransforms = customTransforms,
- annotations = annotations.annotations.toList)
+ annotations = annotations.toList)
}
firrtl.Driver.execute(optionsManager)
@@ -65,7 +65,7 @@ trait FirrtlRunners extends BackendCompilationUtilities {
srcDir: String,
verilogPrefixes: Seq[String] = Seq.empty,
customTransforms: Seq[Transform] = Seq.empty,
- annotations: AnnotationMap = new AnnotationMap(Seq.empty)) = {
+ annotations: AnnotationSeq = Seq.empty) = {
val testDir = compileFirrtlTest(prefix, srcDir, customTransforms, annotations)
val harness = new File(testDir, s"top.cpp")
copyResourceToFile(cppHarnessResourceName, harness)
@@ -111,8 +111,7 @@ trait FirrtlMatchers extends Matchers {
expected: Seq[String],
compiler: Compiler,
annotations: Seq[Annotation] = Seq.empty) = {
- val annoMap = AnnotationMap(annotations)
- val finalState = compiler.compileAndEmit(CircuitState(parse(input), ChirrtlForm, Some(annoMap)))
+ val finalState = compiler.compileAndEmit(CircuitState(parse(input), ChirrtlForm, annotations))
val lines = finalState.getEmittedCircuit.value split "\n" map normalized
for (e <- expected) {
lines should contain (e)
diff --git a/src/test/scala/firrtlTests/InferReadWriteSpec.scala b/src/test/scala/firrtlTests/InferReadWriteSpec.scala
index 82c9d65f..34e228be 100644
--- a/src/test/scala/firrtlTests/InferReadWriteSpec.scala
+++ b/src/test/scala/firrtlTests/InferReadWriteSpec.scala
@@ -71,8 +71,8 @@ circuit sram6t :
T_5 <= io.wdata
""".stripMargin
- val annotationMap = AnnotationMap(Seq(memlib.InferReadWriteAnnotation("sram6t")))
- val res = compileAndEmit(CircuitState(parse(input), ChirrtlForm, Some(annotationMap)))
+ val annos = Seq(memlib.InferReadWriteAnnotation)
+ val res = compileAndEmit(CircuitState(parse(input), ChirrtlForm, annos))
// Check correctness of firrtl
parse(res.getEmittedCircuit.value)
}
@@ -102,8 +102,8 @@ circuit sram6t :
io.dataOut <= _T_22
""".stripMargin
- val annotationMap = AnnotationMap(Seq(memlib.InferReadWriteAnnotation("sram6t")))
- val res = compileAndEmit(CircuitState(parse(input), ChirrtlForm, Some(annotationMap)))
+ val annos = Seq(memlib.InferReadWriteAnnotation)
+ val res = compileAndEmit(CircuitState(parse(input), ChirrtlForm, annos))
// Check correctness of firrtl
parse(res.getEmittedCircuit.value)
}
@@ -133,9 +133,9 @@ circuit sram6t :
T_5 <= io.wdata
""".stripMargin
- val annotationMap = AnnotationMap(Seq(memlib.InferReadWriteAnnotation("sram6t")))
+ val annos = Seq(memlib.InferReadWriteAnnotation)
intercept[InferReadWriteCheckException] {
- compileAndEmit(CircuitState(parse(input), ChirrtlForm, Some(annotationMap)))
+ compileAndEmit(CircuitState(parse(input), ChirrtlForm, annos))
}
}
}
diff --git a/src/test/scala/firrtlTests/PassTests.scala b/src/test/scala/firrtlTests/PassTests.scala
index 6727533e..847643ef 100644
--- a/src/test/scala/firrtlTests/PassTests.scala
+++ b/src/test/scala/firrtlTests/PassTests.scala
@@ -21,7 +21,7 @@ abstract class SimpleTransformSpec extends FlatSpec with FirrtlMatchers with Com
// Executes the test. Call in tests.
// annotations cannot have default value because scalatest trait Suite has a default value
def execute(input: String, check: String, annotations: Seq[Annotation]): Unit = {
- val finalState = compileAndEmit(CircuitState(parse(input), ChirrtlForm, Some(AnnotationMap(annotations))))
+ val finalState = compileAndEmit(CircuitState(parse(input), ChirrtlForm, annotations))
val actual = RemoveEmpty.run(parse(finalState.getEmittedCircuit.value)).serialize
val expected = parse(check).serialize
logger.debug(actual)
@@ -32,7 +32,7 @@ abstract class SimpleTransformSpec extends FlatSpec with FirrtlMatchers with Com
// No default to be consistent with execute
def failingexecute(input: String, annotations: Seq[Annotation]): Exception = {
intercept[PassExceptions] {
- compile(CircuitState(parse(input), ChirrtlForm, Some(AnnotationMap(annotations))), Seq.empty)
+ compile(CircuitState(parse(input), ChirrtlForm, annotations), Seq.empty)
}
}
}
diff --git a/src/test/scala/firrtlTests/ReplSeqMemTests.scala b/src/test/scala/firrtlTests/ReplSeqMemTests.scala
index 7cbfeafe..dcc23235 100644
--- a/src/test/scala/firrtlTests/ReplSeqMemTests.scala
+++ b/src/test/scala/firrtlTests/ReplSeqMemTests.scala
@@ -63,8 +63,8 @@ circuit Top :
io2.commit_entry.bits.info <- R1
""".stripMargin
val confLoc = "ReplSeqMemTests.confTEMP"
- val aMap = AnnotationMap(Seq(ReplSeqMemAnnotation("-c:Top:-o:"+confLoc)))
- val res = compileAndEmit(CircuitState(parse(input), ChirrtlForm, Some(aMap)))
+ val annos = Seq(ReplSeqMemAnnotation.parse("-c:Top:-o:"+confLoc))
+ val res = compileAndEmit(CircuitState(parse(input), ChirrtlForm, annos))
// Check correctness of firrtl
println(res.annotations)
parse(res.getEmittedCircuit.value)
@@ -86,8 +86,8 @@ circuit Top :
write mport T_155 = mem[p_address], clock
""".stripMargin
val confLoc = "ReplSeqMemTests.confTEMP"
- val aMap = AnnotationMap(Seq(ReplSeqMemAnnotation("-c:Top:-o:"+confLoc)))
- val res = compileAndEmit(CircuitState(parse(input), ChirrtlForm, Some(aMap)))
+ val annos = Seq(ReplSeqMemAnnotation.parse("-c:Top:-o:"+confLoc))
+ val res = compileAndEmit(CircuitState(parse(input), ChirrtlForm, annos))
// Check correctness of firrtl
parse(res.getEmittedCircuit.value)
(new java.io.File(confLoc)).delete()
@@ -111,8 +111,8 @@ circuit CustomMemory :
skip
""".stripMargin
val confLoc = "ReplSeqMemTests.confTEMP"
- val aMap = AnnotationMap(Seq(ReplSeqMemAnnotation("-c:CustomMemory:-o:"+confLoc)))
- val res = compileAndEmit(CircuitState(parse(input), ChirrtlForm, Some(aMap)))
+ val annos = Seq(ReplSeqMemAnnotation.parse("-c:CustomMemory:-o:"+confLoc))
+ val res = compileAndEmit(CircuitState(parse(input), ChirrtlForm, annos))
// Check correctness of firrtl
parse(res.getEmittedCircuit.value)
(new java.io.File(confLoc)).delete()
@@ -136,8 +136,8 @@ circuit CustomMemory :
skip
""".stripMargin
val confLoc = "ReplSeqMemTests.confTEMP"
- val aMap = AnnotationMap(Seq(ReplSeqMemAnnotation("-c:CustomMemory:-o:"+confLoc)))
- val res = compileAndEmit(CircuitState(parse(input), ChirrtlForm, Some(aMap)))
+ val annos = Seq(ReplSeqMemAnnotation.parse("-c:CustomMemory:-o:"+confLoc))
+ val res = compileAndEmit(CircuitState(parse(input), ChirrtlForm, annos))
// Check correctness of firrtl
parse(res.getEmittedCircuit.value)
(new java.io.File(confLoc)).delete()
@@ -209,10 +209,10 @@ circuit CustomMemory :
skip
"""
val confLoc = "ReplSeqMemTests.confTEMP"
- val aMap = AnnotationMap(Seq(
- ReplSeqMemAnnotation("-c:CustomMemory:-o:"+confLoc),
- NoDedupMemAnnotation(ComponentName("mem_0", ModuleName("CustomMemory",CircuitName("CustomMemory"))))))
- val res = compileAndEmit(CircuitState(parse(input), ChirrtlForm, Some(aMap)))
+ val annos = Seq(
+ ReplSeqMemAnnotation.parse("-c:CustomMemory:-o:"+confLoc),
+ NoDedupMemAnnotation(ComponentName("mem_0", ModuleName("CustomMemory",CircuitName("CustomMemory")))))
+ val res = compileAndEmit(CircuitState(parse(input), ChirrtlForm, annos))
// Check correctness of firrtl
val circuit = parse(res.getEmittedCircuit.value)
val numExtMods = circuit.modules.count {
@@ -249,10 +249,10 @@ circuit CustomMemory :
skip
"""
val confLoc = "ReplSeqMemTests.confTEMP"
- val aMap = AnnotationMap(Seq(
- ReplSeqMemAnnotation("-c:CustomMemory:-o:"+confLoc),
- NoDedupMemAnnotation(ComponentName("mem_1", ModuleName("CustomMemory",CircuitName("CustomMemory"))))))
- val res = compileAndEmit(CircuitState(parse(input), ChirrtlForm, Some(aMap)))
+ val annos = Seq(
+ ReplSeqMemAnnotation.parse("-c:CustomMemory:-o:"+confLoc),
+ NoDedupMemAnnotation(ComponentName("mem_1", ModuleName("CustomMemory",CircuitName("CustomMemory")))))
+ val res = compileAndEmit(CircuitState(parse(input), ChirrtlForm, annos))
// Check correctness of firrtl
val circuit = parse(res.getEmittedCircuit.value)
val numExtMods = circuit.modules.count {
@@ -285,8 +285,8 @@ circuit CustomMemory :
skip
"""
val confLoc = "ReplSeqMemTests.confTEMP"
- val aMap = AnnotationMap(Seq(ReplSeqMemAnnotation("-c:CustomMemory:-o:"+confLoc)))
- val res = compileAndEmit(CircuitState(parse(input), ChirrtlForm, Some(aMap)))
+ val annos = Seq(ReplSeqMemAnnotation.parse("-c:CustomMemory:-o:"+confLoc))
+ val res = compileAndEmit(CircuitState(parse(input), ChirrtlForm, annos))
// Check correctness of firrtl
val circuit = parse(res.getEmittedCircuit.value)
val numExtMods = circuit.modules.count {
diff --git a/src/test/scala/firrtlTests/UnitTests.scala b/src/test/scala/firrtlTests/UnitTests.scala
index 018a35f6..a38a8def 100644
--- a/src/test/scala/firrtlTests/UnitTests.scala
+++ b/src/test/scala/firrtlTests/UnitTests.scala
@@ -24,7 +24,7 @@ class UnitTests extends FirrtlFlatSpec {
val c = transforms.foldLeft(CircuitState(parse(input), UnknownForm)) {
(c: CircuitState, t: Transform) => t.runTransform(c)
}.circuit
- CircuitState(c, UnknownForm, None, None)
+ CircuitState(c, UnknownForm, Seq(), None)
}
"Pull muxes" should "not be exponential in runtime" in {
diff --git a/src/test/scala/firrtlTests/WiringTests.scala b/src/test/scala/firrtlTests/WiringTests.scala
index 6da73157..4f8fd9fe 100644
--- a/src/test/scala/firrtlTests/WiringTests.scala
+++ b/src/test/scala/firrtlTests/WiringTests.scala
@@ -705,7 +705,7 @@ class WiringTests extends FirrtlFlatSpec {
(c: Circuit, p: Pass) => p.run(c)
}
val wiringXForm = new WiringTransform()
- val retC = wiringXForm.execute(CircuitState(c, MidForm, Some(AnnotationMap(Seq(source, sink))), None)).circuit
+ val retC = wiringXForm.execute(CircuitState(c, MidForm, Seq(source, sink))).circuit
(parse(retC.serialize).serialize) should be (parse(check).serialize)
}
@@ -743,7 +743,7 @@ class WiringTests extends FirrtlFlatSpec {
(c: Circuit, p: Pass) => p.run(c)
}
val wiringXForm = new WiringTransform()
- val retC = wiringXForm.execute(CircuitState(c, MidForm, Some(AnnotationMap(Seq(source, sink))), None)).circuit
+ val retC = wiringXForm.execute(CircuitState(c, MidForm, Seq(source, sink))).circuit
(parse(retC.serialize).serialize) should be (parse(check).serialize)
}
@@ -789,7 +789,7 @@ class WiringTests extends FirrtlFlatSpec {
(c: Circuit, p: Pass) => p.run(c)
}
val wiringXForm = new WiringTransform()
- val retC = wiringXForm.execute(CircuitState(c, MidForm, Some(AnnotationMap(Seq(source, sink))), None)).circuit
+ val retC = wiringXForm.execute(CircuitState(c, MidForm, Seq(source, sink))).circuit
(parse(retC.serialize).serialize) should be (parse(check).serialize)
}
diff --git a/src/test/scala/firrtlTests/annotationTests/TargetDirAnnotationSpec.scala b/src/test/scala/firrtlTests/annotationTests/TargetDirAnnotationSpec.scala
index 60cbf0fc..eb061d8f 100644
--- a/src/test/scala/firrtlTests/annotationTests/TargetDirAnnotationSpec.scala
+++ b/src/test/scala/firrtlTests/annotationTests/TargetDirAnnotationSpec.scala
@@ -14,11 +14,9 @@ class FindTargetDirTransform(expected: String) extends Transform {
var run = false
def execute(state: CircuitState): CircuitState = {
run = true
- state.annotations.foreach { aMap =>
- aMap.annotations.collectFirst {
- case TargetDirAnnotation(expected) =>
- foundTargetDir = true
- }
+ state.annotations.collectFirst {
+ case TargetDirAnnotation(expected) =>
+ foundTargetDir = true
}
state
}
diff --git a/src/test/scala/firrtlTests/fixed/FixedPointMathSpec.scala b/src/test/scala/firrtlTests/fixed/FixedPointMathSpec.scala
index 39da2a33..a4319e8b 100644
--- a/src/test/scala/firrtlTests/fixed/FixedPointMathSpec.scala
+++ b/src/test/scala/firrtlTests/fixed/FixedPointMathSpec.scala
@@ -2,7 +2,7 @@
package firrtlTests.fixed
-import firrtl.{CircuitState, ChirrtlForm, LowFirrtlCompiler, Parser, AnnotationMap}
+import firrtl.{CircuitState, ChirrtlForm, LowFirrtlCompiler, Parser}
import firrtl.Parser.IgnoreInfo
import firrtlTests.FirrtlFlatSpec
diff --git a/src/test/scala/firrtlTests/fixed/RemoveFixedTypeSpec.scala b/src/test/scala/firrtlTests/fixed/RemoveFixedTypeSpec.scala
index 34a22c26..8645fa62 100644
--- a/src/test/scala/firrtlTests/fixed/RemoveFixedTypeSpec.scala
+++ b/src/test/scala/firrtlTests/fixed/RemoveFixedTypeSpec.scala
@@ -185,7 +185,7 @@ class RemoveFixedTypeSpec extends FirrtlFlatSpec {
}
val chirrtlTransform = new CheckChirrtlTransform
- chirrtlTransform.execute(CircuitState(parse(input), ChirrtlForm, Some(new AnnotationMap(Seq.empty))))
+ chirrtlTransform.execute(CircuitState(parse(input), ChirrtlForm))
}
"Fixed point numbers" should "remove nested AsFixedPoint" in {
diff --git a/src/test/scala/firrtlTests/transforms/BlacklBoxSourceHelperSpec.scala b/src/test/scala/firrtlTests/transforms/BlacklBoxSourceHelperSpec.scala
index bf294fe9..4c550c46 100644
--- a/src/test/scala/firrtlTests/transforms/BlacklBoxSourceHelperSpec.scala
+++ b/src/test/scala/firrtlTests/transforms/BlacklBoxSourceHelperSpec.scala
@@ -4,39 +4,12 @@ package firrtlTests.transforms
import firrtl.annotations.{Annotation, CircuitName, ModuleName}
import firrtl.transforms._
-import firrtl.{AnnotationMap, FIRRTLException, Transform, VerilogCompiler}
+import firrtl.{FIRRTLException, Transform, VerilogCompiler}
import firrtlTests.{HighTransformSpec, LowTransformSpec}
import org.scalacheck.Test.Failed
import org.scalatest.{FreeSpec, Matchers, Succeeded}
-/**
- * Tests inline instances transformation
- */
-class BlacklBoxSourceHelperSpec extends FreeSpec with Matchers {
- "BlackBoxSourceAnnotations" - {
- val modName = ModuleName("dog", CircuitName("fox"))
- val resource = "file://somefile.v"
-
- "should parse and unparse" in {
-
- val serialized = BlackBoxResource(resource).serialize
- BlackBoxSource.parse(serialized) match {
- case Some(BlackBoxResource(id)) =>
- id should be (resource)
- Succeeded
- case _ => Failed
- }
- }
- "should fail on unsupported kinds" in {
- intercept[FIRRTLException] {
- BlackBoxSourceAnnotation(modName, "bad value")
- }
- BlackBoxSourceAnnotation(modName, BlackBoxResource(resource).serialize).isInstanceOf[Annotation] should be(true)
- }
- }
-}
-
class BlacklBoxSourceHelperTransformSpec extends LowTransformSpec {
def transform: Transform = new BlackBoxSourceHelper
@@ -79,8 +52,8 @@ class BlacklBoxSourceHelperTransformSpec extends LowTransformSpec {
"annotated external modules" should "appear in output directory" in {
val annos = Seq(
- Annotation(moduleName, classOf[BlackBoxSourceHelper], BlackBoxTargetDir("test_run_dir").serialize),
- Annotation(moduleName, classOf[BlackBoxSourceHelper], BlackBoxResource("/blackboxes/AdderExtModule.v").serialize)
+ BlackBoxTargetDirAnno("test_run_dir"),
+ BlackBoxResourceAnno(moduleName, "/blackboxes/AdderExtModule.v")
)
execute(input, output, annos)
diff --git a/src/test/scala/firrtlTests/transforms/DedupTests.scala b/src/test/scala/firrtlTests/transforms/DedupTests.scala
index 74c4b4e7..e88bd506 100644
--- a/src/test/scala/firrtlTests/transforms/DedupTests.scala
+++ b/src/test/scala/firrtlTests/transforms/DedupTests.scala
@@ -8,7 +8,7 @@ import org.scalatest.Matchers
import org.scalatest.junit.JUnitRunner
import firrtl.ir.Circuit
-import firrtl.{Parser, AnnotationMap}
+import firrtl.Parser
import firrtl.passes.PassExceptions
import firrtl.annotations.{
Named,