aboutsummaryrefslogtreecommitdiff
path: root/src/main/scala/firrtl/Driver.scala
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/scala/firrtl/Driver.scala')
-rw-r--r--src/main/scala/firrtl/Driver.scala323
1 files changed, 163 insertions, 160 deletions
diff --git a/src/main/scala/firrtl/Driver.scala b/src/main/scala/firrtl/Driver.scala
index 2a5a379a..6c9e34d5 100644
--- a/src/main/scala/firrtl/Driver.scala
+++ b/src/main/scala/firrtl/Driver.scala
@@ -1,189 +1,192 @@
-/*
-Copyright (c) 2014 - 2016 The Regents of the University of
-California (Regents). All Rights Reserved. Redistribution and use in
-source and binary forms, with or without modification, are permitted
-provided that the following conditions are met:
- * Redistributions of source code must retain the above
- copyright notice, this list of conditions and the following
- two paragraphs of disclaimer.
- * Redistributions in binary form must reproduce the above
- copyright notice, this list of conditions and the following
- two paragraphs of disclaimer in the documentation and/or other materials
- provided with the distribution.
- * Neither the name of the Regents nor the names of its contributors
- may be used to endorse or promote products derived from this
- software without specific prior written permission.
-IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
-SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS,
-ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
-REGENTS HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
-LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-A PARTICULAR PURPOSE. THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF
-ANY, PROVIDED HEREUNDER IS PROVIDED "AS IS". REGENTS HAS NO OBLIGATION
-TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR
-MODIFICATIONS.
-*/
+// See License
package firrtl
+import java.io.FileNotFoundException
+
import scala.io.Source
-import scala.collection.mutable
import Annotations._
-import Utils._
-import Parser.{InfoMode, IgnoreInfo, UseInfo, GenInfo, AppendInfo}
+import Parser.{InfoMode, IgnoreInfo}
+import scala.collection._
+
+/**
+ * The driver provides methods to access the firrtl compiler.
+ * Invoke the compiler with either a FirrtlExecutionOption
+ *
+ * @example
+ * {{{
+ * val optionsManager = ExecutionOptionsManager("firrtl")
+ * optionsManager.register(
+ * FirrtlExecutionOptionsKey ->
+ * new FirrtlExecutionOptions(topName = "Dummy", compilerName = "verilog"))
+ * firrtl.Driver.execute(optionsManager)
+ * }}}
+ * or a series of command line arguments
+ * @example
+ * {{{
+ * firrtl.Driver.execute(Array("--top-name Dummy --compiler verilog".split(" +"))
+ * }}}
+ * each approach has its own endearing aspects
+ * @see firrtlTests.DriverSpec.scala in the test directory for a lot more examples
+ */
object Driver {
- /**
- * Implements the default Firrtl compilers and an inlining pass.
- *
- * Arguments specify the compiler, input file, output file, and
- * optionally the module/instances to inline.
- */
- def main(args: Array[String]) = {
- val usage = """
-Usage: firrtl -i <input_file> -o <output_file> -X <compiler> [options]
- sbt "run-main firrtl.Driver -i <input_file> -o <output_file> -X <compiler> [options]"
-
-Required Arguments:
- -i <filename> Specify the input *.fir file
- -o <filename> Specify the output file
- -X <compiler> Specify the target compiler
- Currently supported: high low verilog
-
-Optional Arguments:
- --info-mode <mode> Specify Info Mode
- Supported modes: ignore, use, gen, append
- --inferRW <circuit> Enable readwrite port inference for the target circuit
- --inline <module>|<instance> Inline a module (e.g. "MyModule") or instance (e.g. "MyModule.myinstance")
-
- --replSeqMem -c:<circuit>:-i:<filename>:-o:<filename>
- *** Replace sequential memories with blackboxes + configuration file
- *** Input configuration file optional
- *** Note: sub-arguments to --replSeqMem should be delimited by : and not white space!
-
- [--help|-h] Print usage string
-"""
-
- def handleInlineOption(value: String): Annotation =
- value.split('.') match {
- case Array(circuit) =>
- passes.InlineAnnotation(CircuitName(circuit), TransID(0))
- case Array(circuit, module) =>
- passes.InlineAnnotation(ModuleName(module, CircuitName(circuit)), TransID(0))
- case Array(circuit, module, inst) =>
- passes.InlineAnnotation(ComponentName(inst, ModuleName(module, CircuitName(circuit))), TransID(0))
- case _ => throw new Exception(s"Bad inline instance/module name: $value" + usage)
- }
-
- def handleInferRWOption(value: String) =
- passes.InferReadWriteAnnotation(value, TransID(-1))
-
- def handleReplSeqMem(value: String) =
- passes.memlib.ReplSeqMemAnnotation(value, TransID(-2))
-
- run(args: Array[String],
- Map( "high" -> new HighFirrtlCompiler(),
- "low" -> new LowFirrtlCompiler(),
- "verilog" -> new VerilogCompiler()),
- Map("--inline" -> handleInlineOption _,
- "--inferRW" -> handleInferRWOption _,
- "--replSeqMem" -> handleReplSeqMem _),
- usage
- )
- }
-
-
// Compiles circuit. First parses a circuit from an input file,
// executes all compiler passes, and writes result to an output
// file.
def compile(
- input: String,
- output: String,
- compiler: Compiler,
+ input: String,
+ output: String,
+ compiler: Compiler,
infoMode: InfoMode = IgnoreInfo,
- annotations: AnnotationMap = new AnnotationMap(Seq.empty)) = {
- val parsedInput = Parser.parse(Source.fromFile(input).getLines, infoMode)
+ annotations: AnnotationMap = new AnnotationMap(Seq.empty)
+ ): String = {
+ val parsedInput = Parser.parse(Source.fromFile(input).getLines(), infoMode)
val outputBuffer = new java.io.CharArrayWriter
compiler.compile(parsedInput, annotations, outputBuffer)
val outputFile = new java.io.PrintWriter(output)
- outputFile.write(outputBuffer.toString)
+ val outputString = outputBuffer.toString
+ outputFile.write(outputString)
outputFile.close()
+ outputString
}
/**
- * Runs a Firrtl compiler.
- *
- * @param args list of commandline arguments
- * @param compilers mapping a compiler name to a compiler
- * @param customOptions mapping a custom option name to a function that returns an annotation
- * @param usage describes the commandline API
- */
- def run(args: Array[String], compilers: Map[String,Compiler], customOptions: Map[String, String=>Annotation], usage: String) = {
- /**
- * Keys commandline values specified by user in OptionMap
- */
- sealed trait CompilerOption
- case object InputFileName extends CompilerOption
- case object OutputFileName extends CompilerOption
- case object CompilerName extends CompilerOption
- case object AnnotationOption extends CompilerOption
- case object InfoModeOption extends CompilerOption
- /**
- * Maps compiler option to user-specified value
- */
- type OptionMap = Map[CompilerOption, String]
-
- /**
- * Populated by custom annotations returned from corresponding function
- * held in customOptions
- */
- val annotations = mutable.ArrayBuffer[Annotation]()
- def nextOption(map: OptionMap, list: List[String]): OptionMap = {
- list match {
- case Nil => map
- case "-i" :: value :: tail =>
- nextOption(map + (InputFileName -> value), tail)
- case "-o" :: value :: tail =>
- nextOption(map + (OutputFileName -> value), tail)
- case "-X" :: value :: tail =>
- nextOption(map + (CompilerName -> value), tail)
- case "--info-mode" :: value :: tail =>
- nextOption(map + (InfoModeOption -> value), tail)
- case flag :: value :: tail if customOptions.contains(flag) =>
- annotations += customOptions(flag)(value)
- nextOption(map, tail)
- case ("-h" | "--help") :: tail => println(usage); sys.exit(0)
- case option :: tail =>
- throw new Exception("Unknown option " + option + usage)
- }
- }
+ * print the message in red
+ *
+ * @param message error message
+ */
+ def dramaticError(message: String): Unit = {
+ println(Console.RED + "-"*78)
+ println(s"Error: $message")
+ println("-"*78 + Console.RESET)
+ }
- val arglist = args.toList
- val options = nextOption(Map[CompilerOption, String](), arglist)
+ /**
+ * Run the firrtl compiler using the provided option
+ *
+ * @param optionsManager the desired flags to the compiler
+ * @return a FirrtlExectionResult indicating success or failure, provide access to emitted data on success
+ * for downstream tools as desired
+ */
+ def execute(optionsManager: ExecutionOptionsManager with HasFirrtlOptions): FirrtlExecutionResult = {
+ val firrtlConfig = optionsManager.firrtlOptions
+
+ val firrtlSource = firrtlConfig.firrtlSource match {
+ case Some(text) => text.split("\n").toIterator
+ case None =>
+ if(optionsManager.topName.isEmpty && firrtlConfig.inputFileNameOverride.isEmpty) {
+ val message = "either top-name or input-file-override must be set"
+ dramaticError(message)
+ return FirrtlExecutionFailure(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)
+ }
+ val inputFileName = firrtlConfig.getInputFileName(optionsManager)
+ try {
+ io.Source.fromFile(inputFileName).getLines()
+ }
+ catch {
+ case e: FileNotFoundException =>
+ val message = s"Input file $inputFileName not found"
+ dramaticError(message)
+ return FirrtlExecutionFailure(message)
+ }
+ }
- // Get input circuit/output filenames
- val input = options.getOrElse(InputFileName, throw new Exception("No input file provided!" + usage))
- val output = options.getOrElse(OutputFileName, throw new Exception("No output file provided!" + usage))
+ val parsedInput = Parser.parse(firrtlSource, firrtlConfig.infoMode)
+ val outputBuffer = new java.io.CharArrayWriter
+ firrtlConfig.compiler.compile(parsedInput, new AnnotationMap(Seq.empty), outputBuffer)
- val infoMode = options.get(InfoModeOption) match {
- case (Some("append") | None) => AppendInfo(input)
- case Some("use") => UseInfo
- case Some("ignore") => IgnoreInfo
- case Some("gen") => GenInfo(input)
- case Some(other) => throw new Exception("Unknown info mode option: " + other + usage)
- }
+ val outputFileName = firrtlConfig.getOutputFileName(optionsManager)
+ val outputFile = new java.io.PrintWriter(outputFileName)
+ val outputString = outputBuffer.toString
+ outputFile.write(outputString)
+ outputFile.close()
- // Execute selected compiler - error if not recognized compiler
- options.get(CompilerName) match {
- case Some(name) =>
- compilers.get(name) match {
- case Some(compiler) => compile(input, output, compiler, infoMode, new AnnotationMap(annotations.toSeq))
- case None => throw new Exception("Unknown compiler option: " + name + usage)
+ FirrtlExecutionSuccess(firrtlConfig.compilerName, outputBuffer.toString)
+ }
+
+ /**
+ * this is a wrapper for execute that builds the options from a standard command line args,
+ * for example, like strings passed to main()
+ *
+ * @param args an Array of string s containing legal arguments
+ * @return
+ */
+ def execute(args: Array[String]): FirrtlExecutionResult = {
+ val optionsManager = new ExecutionOptionsManager("firrtl") with HasFirrtlOptions
+
+ optionsManager.parse(args) match {
+ case true =>
+ execute(optionsManager) match {
+ case success: FirrtlExecutionSuccess =>
+ success
+ case failure: FirrtlExecutionFailure =>
+ optionsManager.showUsageAsError()
+ failure
+ case result =>
+ throw new Exception(s"Error: Unknown Firrtl Execution result $result")
}
- case None => throw new Exception("No specified compiler option." + usage)
+ case _ =>
+ FirrtlExecutionFailure("Could not parser command line options")
}
}
+
+ def main(args: Array[String]): Unit = {
+ execute(args)
+ }
}
+
+object FileUtils {
+ /**
+ * recursive create directory and all parents
+ *
+ * @param directoryName a directory string with one or more levels
+ * @return
+ */
+ def makeDirectory(directoryName: String): Boolean = {
+ val dirFile = new java.io.File(directoryName)
+ if(dirFile.exists()) {
+ if(dirFile.isDirectory) {
+ true
+ }
+ else {
+ false
+ }
+ }
+ else {
+ dirFile.mkdirs()
+ }
+ }
+
+ /**
+ * recursively delete all directories in a relative path
+ * DO NOT DELETE absolute paths
+ *
+ * @param directoryPathName a directory hierarchy to delete
+ */
+ def deleteDirectoryHierarchy(directoryPathName: String): Unit = {
+ if(directoryPathName.isEmpty || directoryPathName.startsWith("/")) {
+ // don't delete absolute path
+ }
+ else {
+ val directory = new java.io.File(directoryPathName)
+ if(directory.isDirectory) {
+ directory.delete()
+ val directories = directoryPathName.split("/+").reverse.tail
+ if (directories.nonEmpty) {
+ deleteDirectoryHierarchy(directories.reverse.mkString("/"))
+ }
+ }
+ }
+ }
+} \ No newline at end of file