aboutsummaryrefslogtreecommitdiff
path: root/src/main/scala/firrtl/options/phases
diff options
context:
space:
mode:
authorJack Koenig2019-04-26 13:10:44 -0700
committerGitHub2019-04-26 13:10:44 -0700
commita7cf6ff3416a11088d811a435ba71fd36b191fb4 (patch)
tree79e2e8c5753903ca6d14e9b952c26a07442bd980 /src/main/scala/firrtl/options/phases
parent99ae1d6649f1731c5dec2098b10733735232b72c (diff)
parentef8f06f23b9ee6cf86de2450752dfd0fcd32da80 (diff)
Merge pull request #1005 from freechipsproject/f764.7
Stage/Phase
Diffstat (limited to 'src/main/scala/firrtl/options/phases')
-rw-r--r--src/main/scala/firrtl/options/phases/AddDefaults.scala8
-rw-r--r--src/main/scala/firrtl/options/phases/Checks.scala43
-rw-r--r--src/main/scala/firrtl/options/phases/ConvertLegacyAnnotations.scala2
-rw-r--r--src/main/scala/firrtl/options/phases/DeletedWrapper.scala43
-rw-r--r--src/main/scala/firrtl/options/phases/GetIncludes.scala11
-rw-r--r--src/main/scala/firrtl/options/phases/WriteOutputAnnotations.scala36
6 files changed, 130 insertions, 13 deletions
diff --git a/src/main/scala/firrtl/options/phases/AddDefaults.scala b/src/main/scala/firrtl/options/phases/AddDefaults.scala
index f0749b22..2d4e4e40 100644
--- a/src/main/scala/firrtl/options/phases/AddDefaults.scala
+++ b/src/main/scala/firrtl/options/phases/AddDefaults.scala
@@ -10,14 +10,10 @@ import firrtl.options.{Phase, StageOption, TargetDirAnnotation}
* This currently only adds a [[TargetDirAnnotation]]. This isn't necessary for a [[StageOptionsView]], but downstream
* tools may expect a [[TargetDirAnnotation]] to exist.
*/
-object AddDefaults extends Phase {
+class AddDefaults extends Phase {
def transform(annotations: AnnotationSeq): AnnotationSeq = {
- var td = true
- annotations.collect { case a: StageOption => a }.map {
- case _: TargetDirAnnotation => td = false
- case _ =>
- }
+ val td = annotations.collectFirst{ case a: TargetDirAnnotation => a}.isEmpty
(if (td) Seq(TargetDirAnnotation()) else Seq()) ++
annotations
diff --git a/src/main/scala/firrtl/options/phases/Checks.scala b/src/main/scala/firrtl/options/phases/Checks.scala
new file mode 100644
index 00000000..0691e9b0
--- /dev/null
+++ b/src/main/scala/firrtl/options/phases/Checks.scala
@@ -0,0 +1,43 @@
+// See LICENSE for license details.
+
+package firrtl.options.phases
+
+import firrtl.AnnotationSeq
+import firrtl.annotations.Annotation
+import firrtl.options.{OptionsException, OutputAnnotationFileAnnotation, Phase, TargetDirAnnotation}
+
+/** [[firrtl.options.Phase Phase]] that validates an [[AnnotationSeq]]. If successful, views of this [[AnnotationSeq]]
+ * as [[StageOptions]] are guaranteed to succeed.
+ */
+class Checks extends Phase {
+
+ /** Validate an [[AnnotationSeq]] for [[StageOptions]]
+ * @throws OptionsException if annotations are invalid
+ */
+ def transform(annotations: AnnotationSeq): AnnotationSeq = {
+
+ val td, outA = collection.mutable.ListBuffer[Annotation]()
+ annotations.foreach {
+ case a: TargetDirAnnotation => td += a
+ case a: OutputAnnotationFileAnnotation => outA += a
+ case _ =>
+ }
+
+ if (td.size != 1) {
+ val d = td.map{ case TargetDirAnnotation(x) => x }
+ throw new OptionsException(
+ s"""|Exactly one target directory must be specified, but found `${d.mkString(", ")}` specified via:
+ | - explicit target directory: -td, --target-dir, TargetDirAnnotation
+ | - fallback default value""".stripMargin )}
+
+ if (outA.size > 1) {
+ val x = outA.map{ case OutputAnnotationFileAnnotation(x) => x }
+ throw new OptionsException(
+ s"""|At most one output annotation file can be specified, but found '${x.mkString(", ")}' specified via:
+ | - an option or annotation: -foaf, --output-annotation-file, OutputAnnotationFileAnnotation"""
+ .stripMargin )}
+
+ annotations
+ }
+
+}
diff --git a/src/main/scala/firrtl/options/phases/ConvertLegacyAnnotations.scala b/src/main/scala/firrtl/options/phases/ConvertLegacyAnnotations.scala
index 7ff05370..39f59572 100644
--- a/src/main/scala/firrtl/options/phases/ConvertLegacyAnnotations.scala
+++ b/src/main/scala/firrtl/options/phases/ConvertLegacyAnnotations.scala
@@ -7,7 +7,7 @@ import firrtl.annotations.LegacyAnnotation
import firrtl.options.Phase
/** Convert any [[firrtl.annotations.LegacyAnnotation LegacyAnnotation]]s to non-legacy variants */
-object ConvertLegacyAnnotations extends Phase {
+class ConvertLegacyAnnotations extends Phase {
def transform(annotations: AnnotationSeq): AnnotationSeq = LegacyAnnotation.convertLegacyAnnos(annotations)
diff --git a/src/main/scala/firrtl/options/phases/DeletedWrapper.scala b/src/main/scala/firrtl/options/phases/DeletedWrapper.scala
new file mode 100644
index 00000000..0a959f32
--- /dev/null
+++ b/src/main/scala/firrtl/options/phases/DeletedWrapper.scala
@@ -0,0 +1,43 @@
+// See LICENSE for license details.
+
+package firrtl.options.phases
+
+import firrtl.AnnotationSeq
+import firrtl.annotations.DeletedAnnotation
+import firrtl.options.{Phase, Translator}
+
+import scala.collection.mutable
+
+/** Wrap a [[firrtl.options.Phase Phase]] such that any [[firrtl.annotations.Annotation Annotation]] removed by the
+ * wrapped [[firrtl.options.Phase Phase]] will be added as [[firrtl.annotations.DeletedAnnotation DeletedAnnotation]]s.
+ * @param p a [[firrtl.options.Phase Phase]] to wrap
+ */
+class DeletedWrapper(p: Phase) extends Phase with Translator[AnnotationSeq, (AnnotationSeq, AnnotationSeq)] {
+
+ override lazy val name: String = p.name
+
+ def aToB(a: AnnotationSeq): (AnnotationSeq, AnnotationSeq) = (a, a)
+
+ def bToA(b: (AnnotationSeq, AnnotationSeq)): AnnotationSeq = {
+
+ val (in, out) = (mutable.LinkedHashSet() ++ b._1, mutable.LinkedHashSet() ++ b._2)
+
+ (in -- out).map {
+ case DeletedAnnotation(n, a) => DeletedAnnotation(s"$n+$name", a)
+ case a => DeletedAnnotation(name, a)
+ }.toSeq ++ b._2
+
+ }
+
+ def internalTransform(b: (AnnotationSeq, AnnotationSeq)): (AnnotationSeq, AnnotationSeq) = (b._1, p.transform(b._2))
+
+}
+
+object DeletedWrapper {
+
+ /** Wrap a [[firrtl.options.Phase Phase]] in a [[DeletedWrapper]]
+ * @param p a [[firrtl.options.Phase Phase]] to wrap
+ */
+ def apply(p: Phase): DeletedWrapper = new DeletedWrapper(p)
+
+}
diff --git a/src/main/scala/firrtl/options/phases/GetIncludes.scala b/src/main/scala/firrtl/options/phases/GetIncludes.scala
index 8156dbbf..9e198c61 100644
--- a/src/main/scala/firrtl/options/phases/GetIncludes.scala
+++ b/src/main/scala/firrtl/options/phases/GetIncludes.scala
@@ -5,7 +5,7 @@ package firrtl.options.phases
import net.jcazevedo.moultingyaml._
import firrtl.AnnotationSeq
-import firrtl.annotations.{AnnotationFileNotFoundException, DeletedAnnotation, JsonProtocol, LegacyAnnotation}
+import firrtl.annotations.{AnnotationFileNotFoundException, JsonProtocol, LegacyAnnotation}
import firrtl.annotations.AnnotationYamlProtocol._
import firrtl.options.{InputAnnotationFileAnnotation, Phase, StageUtils}
@@ -15,7 +15,7 @@ import scala.collection.mutable
import scala.util.{Try, Failure}
/** Recursively expand all [[InputAnnotationFileAnnotation]]s in an [[AnnotationSeq]] */
-object GetIncludes extends Phase {
+class GetIncludes extends Phase {
/** Read all [[annotations.Annotation]] from a file in JSON or YAML format
* @param filename a JSON or YAML file of [[annotations.Annotation]]
@@ -46,15 +46,14 @@ object GetIncludes extends Phase {
*/
private def getIncludes(includeGuard: mutable.Set[String] = mutable.Set())
(annos: AnnotationSeq): AnnotationSeq = {
- val phaseName = this.getClass.getName
annos.flatMap {
case a @ InputAnnotationFileAnnotation(value) =>
if (includeGuard.contains(value)) {
- StageUtils.dramaticWarning("Tried to import the same annotation file twice! (Did you include it twice?)")
- Seq(DeletedAnnotation(phaseName, a))
+ StageUtils.dramaticWarning(s"Annotation file ($value) already included! (Did you include it more than once?)")
+ None
} else {
includeGuard += value
- DeletedAnnotation(phaseName, a) +: getIncludes(includeGuard)(readAnnotationsFromFile(value))
+ getIncludes(includeGuard)(readAnnotationsFromFile(value))
}
case x => Seq(x)
}
diff --git a/src/main/scala/firrtl/options/phases/WriteOutputAnnotations.scala b/src/main/scala/firrtl/options/phases/WriteOutputAnnotations.scala
new file mode 100644
index 00000000..bb2a8cd6
--- /dev/null
+++ b/src/main/scala/firrtl/options/phases/WriteOutputAnnotations.scala
@@ -0,0 +1,36 @@
+// See LICENSE for license details.
+
+package firrtl.options.phases
+
+import firrtl.AnnotationSeq
+import firrtl.annotations.{DeletedAnnotation, JsonProtocol}
+import firrtl.options.{Phase, StageOptions, Unserializable, Viewer}
+
+import java.io.PrintWriter
+
+/** [[firrtl.options.Phase Phase]] that writes an [[AnnotationSeq]] to a file. A file is written if and only if a
+ * [[StageOptions]] view has a non-empty [[StageOptions.annotationFileOut annotationFileOut]].
+ */
+class WriteOutputAnnotations extends Phase {
+
+ /** Write the input [[AnnotationSeq]] to a fie. */
+ def transform(annotations: AnnotationSeq): AnnotationSeq = {
+ val sopts = Viewer[StageOptions].view(annotations)
+ val serializable = annotations.filter{
+ case _: Unserializable => false
+ case _: DeletedAnnotation => sopts.writeDeleted
+ case _ => true
+ }
+
+ sopts.annotationFileOut match {
+ case None =>
+ case Some(file) =>
+ val pw = new PrintWriter(sopts.getBuildFileName(file, Some(".anno.json")))
+ pw.write(JsonProtocol.serialize(serializable))
+ pw.close()
+ }
+
+ annotations
+ }
+
+}