diff options
| author | Jack Koenig | 2019-04-26 13:10:44 -0700 |
|---|---|---|
| committer | GitHub | 2019-04-26 13:10:44 -0700 |
| commit | a7cf6ff3416a11088d811a435ba71fd36b191fb4 (patch) | |
| tree | 79e2e8c5753903ca6d14e9b952c26a07442bd980 /src/main/scala/firrtl/options/phases | |
| parent | 99ae1d6649f1731c5dec2098b10733735232b72c (diff) | |
| parent | ef8f06f23b9ee6cf86de2450752dfd0fcd32da80 (diff) | |
Merge pull request #1005 from freechipsproject/f764.7
Stage/Phase
Diffstat (limited to 'src/main/scala/firrtl/options/phases')
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 + } + +} |
