summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorSchuyler Eldridge2019-01-14 12:35:02 -0500
committerSchuyler Eldridge2019-05-22 16:17:17 -0400
commit41482912bd2216d4f95043414798120536398e54 (patch)
tree7dfb52badee925ddbba41db0e5e28aaddbed2e6d /src
parent1abb84497315cff795e24afda0e4790fe535132f (diff)
Add Driver Compatibility Layer
This includes phases necessary to provide backwards compatibility with the old Chisel3 Driver. These are placed in a DriverCompatibility object inside chisel3.stage.phases. The following four phases are included: - AddImplicitOutputFile (from a TopNameAnnotation) - AddImplicitOutputAnnotationFile phase - DisableFirrtlStage (to disable ChiselStage running FirrtlStage) - MutateOptionsManager (to update options after ChiselStage) - ReEnableFirrtlStage (to renable FirrtlStage if needed) Additionally, this adds a view of a ChiselExecutionResult for providing the legacy return type of the Chisel Driver. Co-Authored-By: Schuyler Eldridge <schuyler.eldridge@ibm.com> Co-Authored-By: chick <chick@qrhino.com> Signed-off-by: Schuyler Eldridge <schuyler.eldridge@ibm.com>
Diffstat (limited to 'src')
-rw-r--r--src/main/scala/chisel3/stage/package.scala33
-rw-r--r--src/main/scala/chisel3/stage/phases/DriverCompatibility.scala115
-rw-r--r--src/test/scala/chisel3/stage/phases/DriverCompatibilitySpec.scala70
3 files changed, 218 insertions, 0 deletions
diff --git a/src/main/scala/chisel3/stage/package.scala b/src/main/scala/chisel3/stage/package.scala
index 851dd400..67d38ae7 100644
--- a/src/main/scala/chisel3/stage/package.scala
+++ b/src/main/scala/chisel3/stage/package.scala
@@ -3,8 +3,12 @@
package chisel3
import firrtl._
+import firrtl.annotations.DeletedAnnotation
import firrtl.options.OptionsView
+import chisel3.internal.firrtl.{Circuit => ChiselCircuit}
+import chisel3.stage.phases.{Convert, Emitter}
+
package object stage {
implicit object ChiselOptionsView extends OptionsView[ChiselOptions] {
@@ -22,4 +26,33 @@ package object stage {
}
+ private[chisel3] implicit object ChiselExecutionResultView extends OptionsView[ChiselExecutionResult] {
+
+ lazy val dummyWriteEmitted = new firrtl.stage.phases.WriteEmitted
+ lazy val dummyConvert = new Convert
+ lazy val dummyEmitter = new Emitter
+
+ def view(options: AnnotationSeq): ChiselExecutionResult = {
+ var chiselCircuit: Option[ChiselCircuit] = None
+ var chirrtlCircuit: Option[String] = None
+
+ options.foreach {
+ case DeletedAnnotation(dummyConvert.name, ChiselCircuitAnnotation(a)) => chiselCircuit = Some(a)
+ case DeletedAnnotation(dummyEmitter.name, EmittedFirrtlCircuitAnnotation(EmittedFirrtlCircuit(_, a, _))) =>
+ chirrtlCircuit = Some(a)
+ case _ =>
+ }
+
+ val fResult = firrtl.stage.phases.DriverCompatibility.firrtlResultView(options)
+
+ (chiselCircuit, chirrtlCircuit) match {
+ case (None, _) => ChiselExecutionFailure("Failed to elaborate Chisel circuit")
+ case (Some(_), None) => ChiselExecutionFailure("Failed to convert Chisel circuit to FIRRTL")
+ case (Some(a), Some(b)) => ChiselExecutionSuccess( Some(a), b, Some(fResult))
+ }
+
+ }
+
+ }
+
}
diff --git a/src/main/scala/chisel3/stage/phases/DriverCompatibility.scala b/src/main/scala/chisel3/stage/phases/DriverCompatibility.scala
new file mode 100644
index 00000000..b7674aa1
--- /dev/null
+++ b/src/main/scala/chisel3/stage/phases/DriverCompatibility.scala
@@ -0,0 +1,115 @@
+// See LICENSE for license details.
+
+package chisel3.stage.phases
+
+import firrtl.{AnnotationSeq, ExecutionOptionsManager, HasFirrtlOptions}
+import firrtl.annotations.NoTargetAnnotation
+import firrtl.options.{OutputAnnotationFileAnnotation, Phase}
+import firrtl.stage.{FirrtlCircuitAnnotation, RunFirrtlTransformAnnotation}
+import firrtl.stage.phases.DriverCompatibility.TopNameAnnotation
+
+import chisel3.HasChiselExecutionOptions
+import chisel3.stage.{NoRunFirrtlCompilerAnnotation, ChiselOutputFileAnnotation}
+
+/** This provides components of a compatibility wrapper around Chisel's deprecated [[chisel3.Driver]].
+ *
+ * Primarily, this object includes [[firrtl.options.Phase Phase]]s that generate [[firrtl.annotations.Annotation]]s
+ * derived from the deprecated [[firrtl.stage.phases.DriverCompatibility.TopNameAnnotation]].
+ */
+object DriverCompatibility {
+
+ /** Adds a [[ChiselOutputFileAnnotation]] derived from a [[TopNameAnnotation]] if no [[ChiselOutputFileAnnotation]]
+ * already exists. If no [[TopNameAnnotation]] exists, then no [[firrtl.stage.OutputFileAnnotation]] is added. ''This is not a
+ * replacement for [[chisel3.stage.phases.AddImplicitOutputFile AddImplicitOutputFile]] as this only adds an output
+ * file based on a discovered top name and not on a discovered elaborated circuit.'' Consequently, this will provide
+ * the correct behavior before a circuit has been elaborated.
+ * @note the output suffix is unspecified and will be set by the underlying [[firrtl.EmittedComponent]]
+ */
+ private[chisel3] class AddImplicitOutputFile extends Phase {
+
+ def transform(annotations: AnnotationSeq): AnnotationSeq = {
+ val hasOutputFile = annotations
+ .collectFirst{ case a: ChiselOutputFileAnnotation => a }
+ .isDefined
+ lazy val top = annotations.collectFirst{ case TopNameAnnotation(a) => a }
+
+ if (!hasOutputFile && top.isDefined) {
+ ChiselOutputFileAnnotation(top.get) +: annotations
+ } else {
+ annotations
+ }
+ }
+ }
+
+ /** If a [[firrtl.options.OutputAnnotationFileAnnotation]] does not exist, this adds one derived from a
+ * [[TopNameAnnotation]]. ''This is not a replacement for [[chisel3.stage.phases.AddImplicitOutputAnnotationFile]] as
+ * this only adds an output annotation file based on a discovered top name.'' Consequently, this will provide the
+ * correct behavior before a circuit has been elaborated.
+ * @note the output suffix is unspecified and will be set by [[firrtl.options.phases.WriteOutputAnnotations]]
+ */
+ private[chisel3] class AddImplicitOutputAnnotationFile extends Phase {
+
+ def transform(annotations: AnnotationSeq): AnnotationSeq =
+ annotations
+ .collectFirst{ case _: OutputAnnotationFileAnnotation => annotations }
+ .getOrElse{
+ val top = annotations.collectFirst{ case TopNameAnnotation(a) => a }
+ if (top.isDefined) {
+ OutputAnnotationFileAnnotation(top.get) +: annotations
+ } else {
+ annotations
+ }
+ }
+ }
+
+ private[chisel3] case object RunFirrtlCompilerAnnotation extends NoTargetAnnotation
+
+ /** Disables the execution of [[firrtl.stage.FirrtlStage]]. This can be used to call [[chisel3.stage.ChiselStage]] and
+ * guarantee that the FIRRTL compiler will not run. This is necessary for certain [[chisel3.Driver]] compatibility
+ * situations where you need to do something between Chisel compilation and FIRRTL compilations, e.g., update a
+ * mutable data structure.
+ */
+ private[chisel3] class DisableFirrtlStage extends Phase {
+
+ def transform(annotations: AnnotationSeq): AnnotationSeq = annotations
+ .collectFirst { case NoRunFirrtlCompilerAnnotation => annotations }
+ .getOrElse { Seq(RunFirrtlCompilerAnnotation, NoRunFirrtlCompilerAnnotation) ++ annotations }
+ }
+
+ private[chisel3] class ReEnableFirrtlStage extends Phase {
+
+ def transform(annotations: AnnotationSeq): AnnotationSeq = annotations
+ .collectFirst { case RunFirrtlCompilerAnnotation =>
+ val a: AnnotationSeq = annotations.filter {
+ case NoRunFirrtlCompilerAnnotation | RunFirrtlCompilerAnnotation => false
+ case _ => true
+ }
+ a
+ }
+ .getOrElse{ annotations }
+
+ }
+
+ /** Mutate an input [[firrtl.ExecutionOptionsManager]] based on information encoded in an [[firrtl.AnnotationSeq]].
+ * This is intended to be run between [[chisel3.stage.ChiselStage ChiselStage]] and [[firrtl.stage.FirrtlStage]] if
+ * you want to have backwards compatibility with an [[firrtl.ExecutionOptionsManager]].
+ */
+ private[chisel3] class MutateOptionsManager(
+ optionsManager: ExecutionOptionsManager with HasChiselExecutionOptions with HasFirrtlOptions) extends Phase {
+
+ def transform(annotations: AnnotationSeq): AnnotationSeq = {
+
+ val firrtlCircuit = annotations.collectFirst{ case FirrtlCircuitAnnotation(a) => a }
+ optionsManager.firrtlOptions = optionsManager.firrtlOptions.copy(
+ firrtlCircuit = firrtlCircuit,
+ annotations = optionsManager.firrtlOptions.annotations ++ annotations,
+ customTransforms = optionsManager.firrtlOptions.customTransforms ++
+ annotations.collect{ case RunFirrtlTransformAnnotation(a) => a } )
+
+ annotations
+
+ }
+
+ }
+
+}
diff --git a/src/test/scala/chisel3/stage/phases/DriverCompatibilitySpec.scala b/src/test/scala/chisel3/stage/phases/DriverCompatibilitySpec.scala
new file mode 100644
index 00000000..c478db27
--- /dev/null
+++ b/src/test/scala/chisel3/stage/phases/DriverCompatibilitySpec.scala
@@ -0,0 +1,70 @@
+// See LICENSE for license details.
+
+package chisel3.stage.phases
+
+import org.scalatest.{FlatSpec, Matchers}
+
+import chisel3.stage.{NoRunFirrtlCompilerAnnotation, ChiselOutputFileAnnotation}
+
+import firrtl.options.{OutputAnnotationFileAnnotation, StageOptions}
+import firrtl.options.Viewer.view
+import firrtl.stage.phases.DriverCompatibility.TopNameAnnotation
+
+class DriverCompatibilitySpec extends FlatSpec with Matchers {
+
+ behavior of classOf[DriverCompatibility.AddImplicitOutputFile].toString
+
+ it should "do nothing if a ChiselOutputFileAnnotation is present" in {
+ val annotations = Seq(
+ ChiselOutputFileAnnotation("Foo"),
+ TopNameAnnotation("Bar") )
+ (new DriverCompatibility.AddImplicitOutputFile).transform(annotations).toSeq should be (annotations)
+ }
+
+ it should "add a ChiselOutputFileAnnotation derived from a TopNameAnnotation" in {
+ val annotations = Seq( TopNameAnnotation("Bar") )
+ val expected = ChiselOutputFileAnnotation("Bar") +: annotations
+ (new DriverCompatibility.AddImplicitOutputFile).transform(annotations).toSeq should be (expected)
+ }
+
+ behavior of classOf[DriverCompatibility.AddImplicitOutputAnnotationFile].toString
+
+ it should "do nothing if an OutputAnnotationFileAnnotation is present" in {
+ val annotations = Seq(
+ OutputAnnotationFileAnnotation("Foo"),
+ TopNameAnnotation("Bar") )
+ (new DriverCompatibility.AddImplicitOutputAnnotationFile).transform(annotations).toSeq should be (annotations)
+ }
+
+ it should "add an OutputAnnotationFileAnnotation derived from a TopNameAnnotation" in {
+ val annotations = Seq( TopNameAnnotation("Bar") )
+ val expected = OutputAnnotationFileAnnotation("Bar") +: annotations
+ (new DriverCompatibility.AddImplicitOutputAnnotationFile).transform(annotations).toSeq should be (expected)
+ }
+
+ behavior of classOf[DriverCompatibility.DisableFirrtlStage].toString
+
+ it should "add a NoRunFirrtlCompilerAnnotation if one does not exist" in {
+ val annos = Seq(NoRunFirrtlCompilerAnnotation)
+ val expected = DriverCompatibility.RunFirrtlCompilerAnnotation +: annos
+ (new DriverCompatibility.DisableFirrtlStage).transform(Seq.empty).toSeq should be (expected)
+ }
+
+ it should "NOT add a NoRunFirrtlCompilerAnnotation if one already exists" in {
+ val annos = Seq(NoRunFirrtlCompilerAnnotation)
+ (new DriverCompatibility.DisableFirrtlStage).transform(annos).toSeq should be (annos)
+ }
+
+ behavior of classOf[DriverCompatibility.ReEnableFirrtlStage].toString
+
+ it should "NOT strip a NoRunFirrtlCompilerAnnotation if NO RunFirrtlCompilerAnnotation is present" in {
+ val annos = Seq(NoRunFirrtlCompilerAnnotation, DriverCompatibility.RunFirrtlCompilerAnnotation)
+ (new DriverCompatibility.ReEnableFirrtlStage).transform(annos).toSeq should be (Seq.empty)
+ }
+
+ it should "strip a NoRunFirrtlCompilerAnnotation if a RunFirrtlCompilerAnnotation is present" in {
+ val annos = Seq(NoRunFirrtlCompilerAnnotation)
+ (new DriverCompatibility.ReEnableFirrtlStage).transform(annos).toSeq should be (annos)
+ }
+
+}