Skip to content

Commit

Permalink
Make Driver a ChiselStage compatibility layer
Browse files Browse the repository at this point in the history
This converts the original chisel3.Driver to use
chisel3.stage.ChiselStage. This works in the following way:

  1. ExecutionOptions are converted to an AnnotationSeq
  2. The AnnotationSeq is preprocessed using phases contained in the
     FIRRTL and Chisel DriverCompatibility objects.
  3. ChiselStage runs on the preprocessed AnnotationSeq
  4. 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 <[email protected]>
  • Loading branch information
seldridge committed Feb 1, 2019
1 parent e6be4ca commit 6888507
Show file tree
Hide file tree
Showing 2 changed files with 31 additions and 54 deletions.
76 changes: 22 additions & 54 deletions src/main/scala/chisel3/Driver.scala
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,17 @@ package chisel3
import chisel3.internal.ErrorLog
import chisel3.internal.firrtl.Converter
import chisel3.experimental.{RawModule, RunFirrtlTransform}
import chisel3.stage.{ChiselCircuitAnnotation, ChiselGeneratorAnnotation, ChiselStage, ChiselExecutionResultView}
import chisel3.stage.phases.DriverCompatibility

import java.io._
import net.jcazevedo.moultingyaml._

import internal.firrtl._
import firrtl._
import firrtl.annotations.{Annotation, JsonProtocol}
import firrtl.options.Phase
import firrtl.options.Viewer.view
import firrtl.util.{ BackendCompilationUtilities => FirrtlBackendCompilationUtilities }

import _root_.firrtl.annotations.AnnotationYamlProtocol._
Expand Down Expand Up @@ -181,8 +185,22 @@ object Driver extends BackendCompilationUtilities {
def execute(
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(
DriverCompatibility.AddImplicitOutputFile,
DriverCompatibility.AddImplicitOutputAnnotationFile,
firrtl.stage.phases.DriverCompatibility.AddImplicitOutputFile,
firrtl.stage.phases.DriverCompatibility.AddImplicitEmitter,
ChiselStage
)

val annosx = try {
phases.foldLeft(annos)( (a, p) => p.runTransform(a) )
} catch {
case ce: ChiselException =>
val stackTrace = if (!optionsManager.chiselOptions.printFullStackTrace) {
Expand All @@ -193,60 +211,10 @@ object Driver extends BackendCompilationUtilities {
sw.toString
}
Predef.augmentString(stackTrace).lines.foreach(line => println(s"${ErrorLog.errTag} $line"))
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)
}

/**
Expand Down
9 changes: 9 additions & 0 deletions src/test/scala/chiselTests/DriverSpec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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()
}
Expand All @@ -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()
}
Expand All @@ -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()
}
Expand Down

0 comments on commit 6888507

Please sign in to comment.