diff options
| author | Schuyler Eldridge | 2019-01-14 12:35:02 -0500 |
|---|---|---|
| committer | Schuyler Eldridge | 2019-05-22 16:17:17 -0400 |
| commit | 41482912bd2216d4f95043414798120536398e54 (patch) | |
| tree | 7dfb52badee925ddbba41db0e5e28aaddbed2e6d /src | |
| parent | 1abb84497315cff795e24afda0e4790fe535132f (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')
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) + } + +} |
