diff options
| author | Jack Koenig | 2018-05-23 11:54:50 -0700 |
|---|---|---|
| committer | GitHub | 2018-05-23 11:54:50 -0700 |
| commit | 87fe48938a3ccc58b1945bae72f0e7305ac14b3b (patch) | |
| tree | 8d809eac737083400ae72b9f11bb2eb3fd91aee1 /src | |
| parent | b1709242b5c7b60e21308642947d292545eb2e37 (diff) | |
Add Circuit as option to FirrtlOptions (#814)
Diffstat (limited to 'src')
| -rw-r--r-- | src/main/scala/firrtl/Driver.scala | 78 | ||||
| -rw-r--r-- | src/main/scala/firrtl/ExecutionOptionsManager.scala | 4 | ||||
| -rw-r--r-- | src/test/scala/firrtlTests/DriverSpec.scala | 43 |
3 files changed, 96 insertions, 29 deletions
diff --git a/src/main/scala/firrtl/Driver.scala b/src/main/scala/firrtl/Driver.scala index 10489da4..72128274 100644 --- a/src/main/scala/firrtl/Driver.scala +++ b/src/main/scala/firrtl/Driver.scala @@ -148,33 +148,38 @@ object Driver { LegacyAnnotation.convertLegacyAnnos(annos) } - /** - * Run the firrtl compiler using the provided option + // Useful for handling erros in the options + case class OptionsException(msg: String) extends Exception(msg) + + /** Get the Circuit from the compile options * - * @param optionsManager the desired flags to the compiler - * @return a FirrtlExecutionResult indicating success or failure, provide access to emitted data on success - * for downstream tools as desired + * Handles the myriad of ways it can be specified */ - //scalastyle:off cyclomatic.complexity method.length - def execute(optionsManager: ExecutionOptionsManager with HasFirrtlOptions): FirrtlExecutionResult = { - def firrtlConfig = optionsManager.firrtlOptions - - Logger.makeScope(optionsManager) { - val firrtlSource = firrtlConfig.firrtlSource match { - case Some(text) => text.split("\n").toIterator - case None => + def getCircuit(optionsManager: ExecutionOptionsManager with HasFirrtlOptions): Try[ir.Circuit] = { + val firrtlConfig = optionsManager.firrtlOptions + Try { + // Check that only one "override" is used + val circuitSources = Map( + "firrtlSource" -> firrtlConfig.firrtlSource.isDefined, + "firrtlCircuit" -> firrtlConfig.firrtlCircuit.isDefined, + "inputFileNameOverride" -> firrtlConfig.inputFileNameOverride.nonEmpty) + if (circuitSources.values.count(x => x) > 1) { + val msg = circuitSources.collect { case (s, true) => s }.mkString(" and ") + + " are set, only 1 can be set at a time!" + throw new OptionsException(msg) + } + firrtlConfig.firrtlCircuit.getOrElse { + val source = firrtlConfig.firrtlSource.map(_.split("\n").toIterator).getOrElse { if (optionsManager.topName.isEmpty && firrtlConfig.inputFileNameOverride.isEmpty) { val message = "either top-name or input-file-override must be set" - dramaticError(message) - return FirrtlExecutionFailure(message) + throw new OptionsException(message) } if ( optionsManager.topName.isEmpty && firrtlConfig.inputFileNameOverride.nonEmpty && firrtlConfig.outputFileNameOverride.isEmpty) { val message = "inputFileName set but neither top-name or output-file-override is set" - dramaticError(message) - return FirrtlExecutionFailure(message) + throw new OptionsException(message) } val inputFileName = firrtlConfig.getInputFileName(optionsManager) try { @@ -183,26 +188,45 @@ object Driver { catch { case _: FileNotFoundException => val message = s"Input file $inputFileName not found" - dramaticError(message) - return FirrtlExecutionFailure(message) + throw new OptionsException(message) } + } + Parser.parse(source, firrtlConfig.infoMode) } + } + } - var maybeFinalState: Option[CircuitState] = None + /** + * Run the firrtl compiler using the provided option + * + * @param optionsManager the desired flags to the compiler + * @return a FirrtlExecutionResult indicating success or failure, provide access to emitted data on success + * for downstream tools as desired + */ + //scalastyle:off cyclomatic.complexity method.length + def execute(optionsManager: ExecutionOptionsManager with HasFirrtlOptions): FirrtlExecutionResult = { + def firrtlConfig = optionsManager.firrtlOptions + Logger.makeScope(optionsManager) { // Wrap compilation in a try/catch to present Scala MatchErrors in a more user-friendly format. - try { - val annos = getAnnotations(optionsManager) + val finalState = try { + val circuit = getCircuit(optionsManager) match { + case Success(c) => c + case Failure(OptionsException(msg)) => + dramaticError(msg) + return FirrtlExecutionFailure(msg) + case Failure(e) => throw e + } - val parsedInput = Parser.parse(firrtlSource, firrtlConfig.infoMode) + val annos = getAnnotations(optionsManager) // Does this need to be before calling compiler? optionsManager.makeTargetDir() - maybeFinalState = Some(firrtlConfig.compiler.compile( - CircuitState(parsedInput, ChirrtlForm, annos), + firrtlConfig.compiler.compile( + CircuitState(circuit, ChirrtlForm, annos), firrtlConfig.customTransforms - )) + ) } catch { // Rethrow the exceptions which are expected or due to the runtime environment (out of memory, stack overflow) @@ -213,8 +237,6 @@ object Driver { case e: Exception => throwInternalError(exception = Some(e)) } - val finalState = maybeFinalState.get - // Do emission // Note: Single emission target assumption is baked in here // Note: FirrtlExecutionSuccess emitted is only used if we're emitting the whole Circuit diff --git a/src/main/scala/firrtl/ExecutionOptionsManager.scala b/src/main/scala/firrtl/ExecutionOptionsManager.scala index 3ee91da0..76426d1e 100644 --- a/src/main/scala/firrtl/ExecutionOptionsManager.scala +++ b/src/main/scala/firrtl/ExecutionOptionsManager.scala @@ -4,6 +4,7 @@ package firrtl import firrtl.annotations._ import firrtl.Parser._ +import firrtl.ir.Circuit import firrtl.passes.memlib.{InferReadWriteAnnotation, ReplSeqMemAnnotation} import firrtl.passes.clocklist.ClockListAnnotation import logger.LogLevel @@ -184,7 +185,8 @@ case class FirrtlExecutionOptions( emitOneFilePerModule: Boolean = false, dontCheckCombLoops: Boolean = false, noDCE: Boolean = false, - annotationFileNames: List[String] = List.empty) + annotationFileNames: List[String] = List.empty, + firrtlCircuit: Option[Circuit] = None) extends ComposableOptions { require(!(emitOneFilePerModule && outputFileNameOverride.nonEmpty), diff --git a/src/test/scala/firrtlTests/DriverSpec.scala b/src/test/scala/firrtlTests/DriverSpec.scala index b0ce0af9..df49e2bb 100644 --- a/src/test/scala/firrtlTests/DriverSpec.scala +++ b/src/test/scala/firrtlTests/DriverSpec.scala @@ -17,6 +17,8 @@ import firrtl._ import firrtl.annotations._ import firrtl.util.BackendCompilationUtilities +import scala.util.{Try, Success, Failure} + class ExceptingTransform extends Transform { def inputForm = HighForm def outputForm = HighForm @@ -124,6 +126,47 @@ class DriverSpec extends FreeSpec with Matchers with BackendCompilationUtilities val outputFileName = firrtlOptions.getTargetFile(optionsManager) outputFileName should be ("carol.v") } + val input = """ + |circuit Top : + | module Top : + | input x : UInt<8> + | output y : UInt<8> + | y <= x""".stripMargin + val circuit = Parser.parse(input.split("\n").toIterator) + "firrtl source can be provided directly" in { + val manager = new ExecutionOptionsManager("test") with HasFirrtlOptions { + commonOptions = CommonOptions(topName = "Top") + firrtlOptions = FirrtlExecutionOptions(firrtlSource = Some(input)) + } + assert(firrtl.Driver.getCircuit(manager).isSuccess) + } + "firrtl Circuits can be provided directly" in { + val manager = new ExecutionOptionsManager("test") with HasFirrtlOptions { + commonOptions = CommonOptions(topName = "Top") + firrtlOptions = FirrtlExecutionOptions(firrtlCircuit = Some(circuit)) + } + firrtl.Driver.getCircuit(manager) shouldBe Success(circuit) + } + "Only one of inputFileNameOverride, firrtlSource, and firrtlCircuit can be used at a time" in { + val manager1 = new ExecutionOptionsManager("test") with HasFirrtlOptions { + commonOptions = CommonOptions(topName = "Top") + firrtlOptions = FirrtlExecutionOptions(firrtlCircuit = Some(circuit), + firrtlSource = Some(input)) + } + val manager2 = new ExecutionOptionsManager("test") with HasFirrtlOptions { + commonOptions = CommonOptions(topName = "Top") + firrtlOptions = FirrtlExecutionOptions(inputFileNameOverride = "hi", + firrtlSource = Some(input)) + } + val manager3 = new ExecutionOptionsManager("test") with HasFirrtlOptions { + commonOptions = CommonOptions(topName = "Top") + firrtlOptions = FirrtlExecutionOptions(inputFileNameOverride = "hi", + firrtlCircuit = Some(circuit)) + } + assert(firrtl.Driver.getCircuit(manager1).isFailure) + assert(firrtl.Driver.getCircuit(manager2).isFailure) + assert(firrtl.Driver.getCircuit(manager3).isFailure) + } "various annotations can be created from command line, currently:" - { "inline annotation" in { val optionsManager = new ExecutionOptionsManager("test") with HasFirrtlOptions |
