aboutsummaryrefslogtreecommitdiff
path: root/src/main/scala/firrtl/transforms
diff options
context:
space:
mode:
authorJack Koenig2018-02-27 18:07:11 -0800
committerGitHub2018-02-27 18:07:11 -0800
commitc7eb1570dfb1c7701ea32d1209982a053f3cec1d (patch)
tree3f509b202d82841c5dad5588d1f953a25d389b44 /src/main/scala/firrtl/transforms
parentb90fc784a1819c1d7905910130a7da022214bc22 (diff)
Refactor Annotations (#721)
- Old Annotation renamed to deprecated LegacyAnnotation - Annotation is now a trait that can be extended - New JsonProtocol for Annotation [de]serialization - Replace AnnotationMap with AnnotationSeq - Deprecate Transform.getMyAnnotations - Update Transforms - Turn on deprecation warnings - Remove deprecated Driver.compile - Make AnnotationTests abstract with Legacy and Json subclasses - Add functionality to convert LegacyAnnotations of built-in annos This will give a noisy warning and is more of a best effort than a robust solution. Fixes #475 Closes #609
Diffstat (limited to 'src/main/scala/firrtl/transforms')
-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
7 files changed, 77 insertions, 159 deletions
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)
}