summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/main/scala/chisel3/stage/phases/Emitter.scala44
-rw-r--r--src/test/scala/chiselTests/stage/phases/EmitterSpec.scala60
2 files changed, 104 insertions, 0 deletions
diff --git a/src/main/scala/chisel3/stage/phases/Emitter.scala b/src/main/scala/chisel3/stage/phases/Emitter.scala
new file mode 100644
index 00000000..1bdb9f8d
--- /dev/null
+++ b/src/main/scala/chisel3/stage/phases/Emitter.scala
@@ -0,0 +1,44 @@
+// See LICENSE for license details.
+
+package chisel3.stage.phases
+
+import firrtl.{AnnotationSeq, EmittedFirrtlCircuit, EmittedFirrtlCircuitAnnotation}
+import firrtl.annotations.DeletedAnnotation
+import firrtl.options.{Phase, StageOptions}
+import firrtl.options.Viewer.view
+
+import chisel3.internal.firrtl.{Emitter => OldEmitter}
+import chisel3.stage.{ChiselCircuitAnnotation, ChiselOptions}
+
+import java.io.{File, FileWriter}
+
+/** Emit a [[chisel3.stage.ChiselCircuitAnnotation]] to a file if a [[chisel3.stage.ChiselOutputFileAnnotation]] is
+ * present. A deleted [[firrtl.EmittedFirrtlCircuitAnnotation]] is added.
+ *
+ * @todo This should be switched to support correct emission of multiple circuits to multiple files. The API should
+ * likely mirror how the [[firrtl.stage.phases.Compiler]] parses annotations into "global" annotations and
+ * left-associative per-circuit annotations.
+ * @todo The use of the deleted [[firrtl.EmittedFirrtlCircuitAnnotation]] is a kludge to provide some breadcrumbs such
+ * that the emitted CHIRRTL can be provided back to the old Driver. This should be removed or a better solution
+ * developed.
+ */
+class Emitter extends Phase {
+
+ def transform(annotations: AnnotationSeq): AnnotationSeq = {
+ val copts = view[ChiselOptions](annotations)
+ val sopts = view[StageOptions](annotations)
+
+ annotations.flatMap {
+ case a: ChiselCircuitAnnotation if copts.outputFile.isDefined =>
+ val file = new File(sopts.getBuildFileName(copts.outputFile.get, Some(".fir")))
+ val emitted = OldEmitter.emit(a.circuit)
+ val w = new FileWriter(file)
+ w.write(emitted)
+ w.close()
+ val anno = EmittedFirrtlCircuitAnnotation(EmittedFirrtlCircuit(a.circuit.name, emitted, ".fir"))
+ Seq(DeletedAnnotation(name, anno), a)
+ case a => Some(a)
+ }
+ }
+
+}
diff --git a/src/test/scala/chiselTests/stage/phases/EmitterSpec.scala b/src/test/scala/chiselTests/stage/phases/EmitterSpec.scala
new file mode 100644
index 00000000..63498adb
--- /dev/null
+++ b/src/test/scala/chiselTests/stage/phases/EmitterSpec.scala
@@ -0,0 +1,60 @@
+// See LICENSE for license details.
+
+package chiselTests.stage.phases
+
+import org.scalatest.{FlatSpec, Matchers}
+
+import chisel3.experimental.RawModule
+import chisel3.stage.{ChiselCircuitAnnotation, ChiselGeneratorAnnotation, ChiselOutputFileAnnotation}
+import chisel3.stage.phases.{Convert, Elaborate, Emitter}
+
+import firrtl.{AnnotationSeq, EmittedFirrtlCircuitAnnotation}
+import firrtl.annotations.DeletedAnnotation
+import firrtl.options.{Phase, TargetDirAnnotation}
+
+import java.io.File
+
+class EmitterSpec extends FlatSpec with Matchers {
+
+ class FooModule extends RawModule { override val desiredName = "Foo" }
+ class BarModule extends RawModule { override val desiredName = "Bar" }
+
+ class Fixture { val phase: Phase = new Emitter }
+
+ behavior of classOf[Emitter].toString
+
+ it should "do nothing if no ChiselOutputFileAnnotations are present" in new Fixture {
+ val dir = new File("test_run_dir/EmitterSpec")
+ val annotations = (new Elaborate).transform(Seq( TargetDirAnnotation(dir.toString),
+ ChiselGeneratorAnnotation(() => new FooModule) ))
+ val annotationsx = phase.transform(annotations)
+
+ val Seq(fooFile, barFile) = Seq("Foo.fir", "Bar.fir").map(f => new File(dir + "/" + f))
+
+ info(s"$fooFile does not exist")
+ fooFile should not (exist)
+
+ info("annotations are unmodified")
+ annotationsx.toSeq should be (annotations.toSeq)
+ }
+
+ it should "emit a ChiselCircuitAnnotation to a specific file" in new Fixture {
+ val dir = new File("test_run_dir/EmitterSpec")
+ val circuit = (new Elaborate)
+ .transform(Seq(ChiselGeneratorAnnotation(() => new BarModule)))
+ .collectFirst{ case a: ChiselCircuitAnnotation => a}
+ .get
+ val annotations = phase.transform(Seq( TargetDirAnnotation(dir.toString),
+ circuit,
+ ChiselOutputFileAnnotation("Baz") ))
+
+ val bazFile = new File(dir + "/Baz.fir")
+
+ info(s"$bazFile exists")
+ bazFile should (exist)
+
+ info("a deleted EmittedFirrtlCircuitAnnotation should be generated")
+ annotations.collect{ case a @ DeletedAnnotation(_, _: EmittedFirrtlCircuitAnnotation) => a }.size should be (1)
+ }
+
+}