From 23641521174ba828feb32dc1c65c13a3d6b46970 Mon Sep 17 00:00:00 2001 From: Schuyler Eldridge Date: Mon, 14 Jan 2019 21:01:29 -0500 Subject: Make Driver a ChiselStage compatibility layer This converts the original chisel3.Driver to use chisel3.stage.ChiselStage. This is implemented in the following way: 1. ExecutionOptions are converted to an AnnotationSeq 2. The AnnotationSeq is preprocessed using phases contained in the Chisel DriverCompatibility objects. One of these *disables* the execution of FirrtlStage by ChiselStage. 3. ChiselStage runs on the preprocessed AnnotationSeq 4. The input ExecutionOptionsManager is mutated based on the output of ChiselStage. 5. The FIRRTL stage is re-enabled if it's supposed to run and selected FIRRTL DriverCompatibility phases run. 6. FirrtlStage runs 7. The output AnnotationSeq is "viewed" as a ChiselExecutionResult This modifies the original DriverSpec to make it more verbose with the addition of info statements. The functionality of the DriverSpec is unmodified. Signed-off-by: Schuyler Eldridge --- src/main/scala/chisel3/Driver.scala | 80 ++++++++++------------------- src/test/scala/chiselTests/DriverSpec.scala | 9 ++++ 2 files changed, 35 insertions(+), 54 deletions(-) (limited to 'src') diff --git a/src/main/scala/chisel3/Driver.scala b/src/main/scala/chisel3/Driver.scala index 303f4599..906ae7fc 100644 --- a/src/main/scala/chisel3/Driver.scala +++ b/src/main/scala/chisel3/Driver.scala @@ -5,11 +5,15 @@ package chisel3 import chisel3.internal.ErrorLog import chisel3.internal.firrtl._ import chisel3.experimental.{RawModule, RunFirrtlTransform} +import chisel3.stage.{ChiselCircuitAnnotation, ChiselGeneratorAnnotation, ChiselStage, ChiselExecutionResultView} +import chisel3.stage.phases.DriverCompatibility import java.io._ import firrtl._ import firrtl.annotations.JsonProtocol +import firrtl.options.Phase +import firrtl.options.Viewer.view import firrtl.util.{BackendCompilationUtilities => FirrtlBackendCompilationUtilities} /** @@ -196,8 +200,26 @@ object Driver extends BackendCompilationUtilities { def execute( // scalastyle:ignore method.length optionsManager: ExecutionOptionsManager with HasChiselExecutionOptions with HasFirrtlOptions, dut: () => RawModule): ChiselExecutionResult = { - val circuitOpt = try { - Some(elaborate(dut)) + + val annos = ChiselGeneratorAnnotation(dut) +: + (optionsManager.chiselOptions.toAnnotations ++ + optionsManager.firrtlOptions.toAnnotations ++ + optionsManager.commonOptions.toAnnotations) + + val phases: Seq[Phase] = + Seq( new DriverCompatibility.AddImplicitOutputFile, + new DriverCompatibility.AddImplicitOutputAnnotationFile, + new DriverCompatibility.DisableFirrtlStage, + new ChiselStage, + new DriverCompatibility.MutateOptionsManager(optionsManager), + new DriverCompatibility.ReEnableFirrtlStage, + new firrtl.stage.phases.DriverCompatibility.AddImplicitOutputFile, + new firrtl.stage.phases.DriverCompatibility.AddImplicitEmitter, + new chisel3.stage.phases.MaybeFirrtlStage ) + .map(firrtl.options.phases.DeletedWrapper(_)) + + val annosx = try { + phases.foldLeft(annos)( (a, p) => p.transform(a) ) } catch { case ce: ChiselException => val stackTrace = if (!optionsManager.chiselOptions.printFullStackTrace) { @@ -208,60 +230,10 @@ object Driver extends BackendCompilationUtilities { sw.toString } Predef.augmentString(stackTrace).lines.foreach(line => println(s"${ErrorLog.errTag} $line")) // scalastyle:ignore regex line.size.limit - None + annos } - circuitOpt.map { circuit => - // this little hack let's us set the topName with the circuit name if it has not been set from args - optionsManager.setTopNameIfNotSet(circuit.name) - - val firrtlOptions = optionsManager.firrtlOptions - val chiselOptions = optionsManager.chiselOptions - - val firrtlCircuit = Converter.convert(circuit) - - // Still emit to leave an artifact (and because this always has been the behavior) - val firrtlString = Driver.emit(circuit) - val firrtlFileName = firrtlOptions.getInputFileName(optionsManager) - val firrtlFile = new File(firrtlFileName) - - val w = new FileWriter(firrtlFile) - w.write(firrtlString) - w.close() - - // Emit the annotations because it has always been the behavior - val annotationFile = new File(optionsManager.getBuildFileName("anno.json")) - val af = new FileWriter(annotationFile) - val firrtlAnnos = circuit.annotations.map(_.toFirrtl) - af.write(JsonProtocol.serialize(firrtlAnnos)) - af.close() - - /** Find the set of transform classes associated with annotations then - * instantiate an instance of each transform - * @note Annotations targeting firrtl.Transform will not result in any - * transform being instantiated - */ - val transforms = circuit.annotations - .collect { case anno: RunFirrtlTransform => anno.transformClass } - .distinct - .filterNot(_ == classOf[firrtl.Transform]) - .map { transformClass: Class[_ <: Transform] => - transformClass.newInstance() - } - /* This passes the firrtl source and annotations directly to firrtl */ - optionsManager.firrtlOptions = optionsManager.firrtlOptions.copy( - firrtlCircuit = Some(firrtlCircuit), - annotations = optionsManager.firrtlOptions.annotations ++ firrtlAnnos, - customTransforms = optionsManager.firrtlOptions.customTransforms ++ transforms.toList) - - val firrtlExecutionResult = if(chiselOptions.runFirrtlCompiler) { - Some(firrtl.Driver.execute(optionsManager)) - } - else { - None - } - ChiselExecutionSuccess(Some(circuit), firrtlString, firrtlExecutionResult) - }.getOrElse(ChiselExecutionFailure("could not elaborate circuit")) + view[ChiselExecutionResult](annosx) } /** diff --git a/src/test/scala/chiselTests/DriverSpec.scala b/src/test/scala/chiselTests/DriverSpec.scala index 612bdef2..8fc58e21 100644 --- a/src/test/scala/chiselTests/DriverSpec.scala +++ b/src/test/scala/chiselTests/DriverSpec.scala @@ -28,6 +28,7 @@ class DriverSpec extends FreeSpec with Matchers { val exts = List("anno.json", "fir", "v") for (ext <- exts) { val dummyOutput = new File(targetDir, "DummyModule" + "." + ext) + info(s"${dummyOutput.toString} exists") dummyOutput.exists() should be(true) dummyOutput.delete() } @@ -44,6 +45,7 @@ class DriverSpec extends FreeSpec with Matchers { val exts = List("anno.json", "fir", "v") for (ext <- exts) { val dummyOutput = new File(targetDir, "dm" + "." + ext) + info(s"${dummyOutput.toString} exists") dummyOutput.exists() should be(true) dummyOutput.delete() } @@ -53,14 +55,21 @@ class DriverSpec extends FreeSpec with Matchers { } } + "execute returns a chisel execution result" in { val targetDir = "test_run_dir" val args = Array("--compiler", "low", "--target-dir", targetDir) + + info("Driver returned a ChiselExecutionSuccess") val result = Driver.execute(args, () => new DummyModule) result shouldBe a[ChiselExecutionSuccess] + + info("emitted circuit included 'circuit DummyModule'") val successResult = result.asInstanceOf[ChiselExecutionSuccess] successResult.emitted should include ("circuit DummyModule") + val dummyOutput = new File(targetDir, "DummyModule.lo.fir") + info(s"${dummyOutput.toString} exists") dummyOutput.exists() should be(true) dummyOutput.delete() } -- cgit v1.2.3