aboutsummaryrefslogtreecommitdiff
path: root/src/main
diff options
context:
space:
mode:
Diffstat (limited to 'src/main')
-rw-r--r--src/main/scala/firrtl/Compiler.scala87
-rw-r--r--src/main/scala/firrtl/Driver.scala46
-rw-r--r--src/main/scala/firrtl/Emitter.scala207
-rw-r--r--src/main/scala/firrtl/ExecutionOptionsManager.scala82
-rw-r--r--src/main/scala/firrtl/LoweringCompilers.scala10
-rw-r--r--src/main/scala/firrtl/annotations/Named.scala6
6 files changed, 376 insertions, 62 deletions
diff --git a/src/main/scala/firrtl/Compiler.scala b/src/main/scala/firrtl/Compiler.scala
index 808fa435..6251fc5c 100644
--- a/src/main/scala/firrtl/Compiler.scala
+++ b/src/main/scala/firrtl/Compiler.scala
@@ -8,6 +8,7 @@ import annotations._
import firrtl.ir.Circuit
import passes.Pass
+import Utils.throwInternalError
/**
* RenameMap maps old names to modified names. Generated by transformations
@@ -33,10 +34,28 @@ case class AnnotationMap(annotations: Seq[Annotation]) {
* Generally only a return value from [[Transform]]s
*/
case class CircuitState(
- circuit: Circuit,
- form: CircuitForm,
- annotations: Option[AnnotationMap] = None,
- renames: Option[RenameMap] = None)
+ circuit: Circuit,
+ form: CircuitForm,
+ annotations: Option[AnnotationMap] = None,
+ renames: Option[RenameMap] = None) {
+
+ /** Helper for getting just an emitted circuit */
+ def emittedCircuitOption: Option[EmittedCircuit] =
+ emittedComponents collectFirst { case x: EmittedCircuit => x }
+ /** Helper for getting an [[EmittedCircuit]] when it is known to exist */
+ def getEmittedCircuit: EmittedCircuit = emittedCircuitOption match {
+ case Some(emittedCircuit) => emittedCircuit
+ case None => throw new FIRRTLException("No EmittedCircuit found! Check Emitter Annotations")
+ }
+ /** Helper function for extracting emitted components from annotations */
+ def emittedComponents: Seq[EmittedComponent] = {
+ val emittedOpt = annotations map (_.annotations collect {
+ case EmittedCircuitAnnotation(x) => x
+ case EmittedModuleAnnotation(x) => x
+ })
+ emittedOpt.getOrElse(Seq.empty)
+ }
+}
/** Current form of the Firrtl Circuit
*
@@ -137,10 +156,9 @@ abstract class PassBasedTransform extends Transform with PassBased {
}
}
-/** Similar to a Transform except that it writes to a Writer instead of returning a
- * CircuitState
- */
-abstract class Emitter {
+/** Defines old API for Emission. Deprecated */
+trait Emitter extends Transform {
+ @deprecated("Use emission annotations instead", "firrtl 1.0")
def emit(state: CircuitState, writer: Writer): Unit
}
@@ -157,12 +175,13 @@ object CompilerUtils {
Seq.empty
} else {
inputForm match {
- case ChirrtlForm => Seq(new ChirrtlToHighFirrtl) ++ getLoweringTransforms(HighForm, outputForm)
+ case ChirrtlForm =>
+ Seq(new ChirrtlToHighFirrtl) ++ getLoweringTransforms(HighForm, outputForm)
case HighForm =>
Seq(new IRToWorkingIR, new ResolveAndCheck, new transforms.DedupModules,
new HighFirrtlToMiddleFirrtl) ++ getLoweringTransforms(MidForm, outputForm)
case MidForm => Seq(new MiddleFirrtlToLowFirrtl) ++ getLoweringTransforms(LowForm, outputForm)
- case LowForm => error("Internal Error! This shouldn't be possible") // should be caught by if above
+ case LowForm => throwInternalError // should be caught by if above
}
}
}
@@ -212,7 +231,9 @@ object CompilerUtils {
}
trait Compiler {
+ // Emitter is still somewhat special because we want to make sure it is run last
def emitter: Emitter
+
/** The sequence of transforms this compiler will execute
* @note The inputForm of a given transform must be higher than or equal to the ouputForm of the
* preceding transform. See [[CircuitForm]]
@@ -242,10 +263,52 @@ trait Compiler {
* @param customTransforms Any custom [[Transform]]s that will be inserted
* into the compilation process by [[CompilerUtils.mergeTransforms]]
*/
+ @deprecated("Please use compileAndEmit or other compile method instead", "firrtl 1.0")
def compile(state: CircuitState,
writer: Writer,
customTransforms: Seq[Transform] = Seq.empty): CircuitState = {
- val allTransforms = CompilerUtils.mergeTransforms(transforms, customTransforms)
+ val finalState = compileAndEmit(state, customTransforms)
+ finalState.emittedCircuitOption match {
+ case Some(emitted) => writer.write(emitted.value)
+ case _ => throwInternalError
+ }
+ finalState
+ }
+
+ /** Perform compilation and emit the whole Circuit
+ *
+ * This is intended as a convenience method wrapping up Annotation creation for the common case.
+ * It creates a [[EmitCircuitAnnotation]] that will be consumed by this Transform's emitter. The
+ * [[EmittedCircuit]] can be extracted from the returned [[CircuitState]] via
+ * [[CircuitState.emittedCircuitOption]]
+ *
+ * @param state The Firrtl AST to compile
+ * @param customTransforms Any custom [[Transform]]s that will be inserted
+ * into the compilation process by [[CompilerUtils.mergeTransforms]]
+ * @return result of compilation with emitted circuit annotated
+ */
+ def compileAndEmit(state: CircuitState,
+ customTransforms: Seq[Transform] = Seq.empty): CircuitState = {
+ val emitAnno = EmitCircuitAnnotation(emitter.getClass)
+ // TODO This is ridiculous. Fix Annotations
+ val annotations = state.annotations.map(_.annotations).getOrElse(Seq.empty)
+ val annotationMap = AnnotationMap(annotations :+ emitAnno)
+
+ // Run compiler
+ compile(state.copy(annotations = Some(annotationMap)), customTransforms)
+ }
+
+ /** Perform compilation
+ *
+ * Emission will only be performed if [[EmitAnnotation]]s are present
+ *
+ * @param state The Firrtl AST to compile
+ * @param customTransforms Any custom [[Transform]]s that will be inserted into the compilation
+ * process by [[CompilerUtils.mergeTransforms]]
+ * @return result of compilation
+ */
+ def compile(state: CircuitState, customTransforms: Seq[Transform]): CircuitState = {
+ val allTransforms = CompilerUtils.mergeTransforms(transforms, customTransforms) :+ emitter
val finalState = allTransforms.foldLeft(state) { (in, xform) =>
val result = Utils.time(s"***${xform.name}***") { xform.execute(in) }
@@ -273,8 +336,6 @@ trait Compiler {
val newAnnotations = AnnotationMap(remappedAnnotations ++ resultAnnotations)
CircuitState(result.circuit, result.form, Some(newAnnotations))
}
-
- emitter.emit(finalState, writer)
finalState
}
}
diff --git a/src/main/scala/firrtl/Driver.scala b/src/main/scala/firrtl/Driver.scala
index 0fdfa768..f321ad16 100644
--- a/src/main/scala/firrtl/Driver.scala
+++ b/src/main/scala/firrtl/Driver.scala
@@ -13,6 +13,7 @@ import Parser.{IgnoreInfo, InfoMode}
import annotations._
import firrtl.annotations.AnnotationYamlProtocol._
import firrtl.transforms.{BlackBoxSourceHelper, BlackBoxTargetDir}
+import Utils.throwInternalError
/**
@@ -41,6 +42,7 @@ object Driver {
// Compiles circuit. First parses a circuit from an input file,
// executes all compiler passes, and writes result to an output
// file.
+ @deprecated("Please use execute", "firrtl 1.0")
def compile(
input: String,
output: String,
@@ -155,20 +157,44 @@ object Driver {
loadAnnotations(optionsManager)
val parsedInput = Parser.parse(firrtlSource, firrtlConfig.infoMode)
- val outputBuffer = new java.io.CharArrayWriter
- firrtlConfig.compiler.compile(
- CircuitState(parsedInput, ChirrtlForm, Some(AnnotationMap(firrtlConfig.annotations))),
- outputBuffer,
+
+ // Does this need to be before calling compiler?
+ optionsManager.makeTargetDir()
+
+ // Output Annotations
+ val outputAnnos = firrtlConfig.getEmitterAnnos(optionsManager)
+
+ val finalState = firrtlConfig.compiler.compile(
+ CircuitState(parsedInput, ChirrtlForm, Some(AnnotationMap(firrtlConfig.annotations ++ outputAnnos))),
firrtlConfig.customTransforms
)
- val outputFileName = firrtlConfig.getOutputFileName(optionsManager)
- val outputFile = new java.io.PrintWriter(outputFileName)
- val outputString = outputBuffer.toString
- outputFile.write(outputString)
- outputFile.close()
+ // Do emission
+ // Note: Single emission target assumption is baked in here
+ // Note: FirrtlExecutionSuccess emitted is only used if we're emitting the whole Circuit
+ val emittedRes = firrtlConfig.getOutputConfig(optionsManager) match {
+ case SingleFile(filename) =>
+ finalState.emittedCircuitOption match {
+ case Some(emitted: EmittedCircuit) =>
+ val outputFile = new java.io.PrintWriter(filename)
+ outputFile.write(emitted.value)
+ outputFile.close()
+ emitted.value
+ case _ => throwInternalError
+ }
+ case OneFilePerModule(dirName) =>
+ val emittedModules = finalState.emittedComponents collect { case x: EmittedModule => x }
+ if (emittedModules.isEmpty) throwInternalError // There should be something
+ emittedModules.foreach { case module =>
+ val filename = optionsManager.getBuildFileName(firrtlConfig.outputSuffix, s"$dirName/${module.name}")
+ val outputFile = new java.io.PrintWriter(filename)
+ outputFile.write(module.value)
+ outputFile.close()
+ }
+ "" // Should we return something different here?
+ }
- FirrtlExecutionSuccess(firrtlConfig.compilerName, outputBuffer.toString)
+ FirrtlExecutionSuccess(firrtlConfig.compilerName, emittedRes)
}
/**
diff --git a/src/main/scala/firrtl/Emitter.scala b/src/main/scala/firrtl/Emitter.scala
index 9ad97859..10d3ae85 100644
--- a/src/main/scala/firrtl/Emitter.scala
+++ b/src/main/scala/firrtl/Emitter.scala
@@ -12,6 +12,7 @@ import scala.io.Source
import firrtl.ir._
import firrtl.passes._
+import firrtl.annotations._
import firrtl.Mappers._
import firrtl.PrimOps._
import firrtl.WrappedExpression._
@@ -22,10 +23,143 @@ import scala.collection.mutable.{ArrayBuffer, LinkedHashMap, HashSet}
case class EmitterException(message: String) extends PassException(message)
-class FirrtlEmitter extends Emitter {
+// ***** Annotations for telling the Emitters what to emit *****
+sealed abstract class EmitAnnotation(marker: String) {
+ // TODO Is there a better way to do Name to indicate don't care?
+ def apply(transform: Class[_ <: Transform]): Annotation =
+ Annotation(CircuitTopName, transform, marker)
+ def unapply(a: Annotation): Boolean = a match {
+ // Assumes transform is already filtered appropriately
+ case Annotation(CircuitTopName, _, str) if str == marker => true
+ case _ => false
+ }
+}
+object EmitCircuitAnnotation extends EmitAnnotation("emitCircuit")
+object EmitAllModulesAnnotation extends EmitAnnotation("emitAllModules")
+
+// ***** Annotations for results of emission *****
+sealed abstract class EmittedComponent {
+ def name: String
+ def value: String
+}
+sealed abstract class EmittedCircuit extends EmittedComponent
+final case class EmittedFirrtlCircuit(name: String, value: String) extends EmittedCircuit
+final case class EmittedVerilogCircuit(name: String, value: String) extends EmittedCircuit
+sealed abstract class EmittedModule extends EmittedComponent
+final case class EmittedFirrtlModule(name: String, value: String) extends EmittedModule
+final case class EmittedVerilogModule(name: String, value: String) extends EmittedModule
+
+/** Super class for Annotations containing emitted components
+ *
+ * @note These annotations cannot be serialized and deserialized to/from an annotation file
+ */
+sealed abstract class EmittedAnnotation[T <: EmittedComponent](marker: String) {
+ // Private datastructure to hold the actual emitted objects
+ // TODO Once annotations can contain arbitrary datastructures, get rid of this
+ private val emittedBuffer = mutable.ArrayBuffer.empty[T]
+
+ def apply(value: T): Annotation = {
+ // Synchronize because of multithreading
+ // This doesn't happen often, shouldn't be a big deal for performance
+ val idx = emittedBuffer.synchronized {
+ emittedBuffer += value
+ emittedBuffer.size - 1
+ }
+ Annotation(CircuitTopName, classOf[Transform], s"$marker:$idx")
+ }
+ def unapply(a: Annotation): Option[T] = a match {
+ // assume transform has been filtered
+ case Annotation(CircuitTopName, _, str) if str.startsWith(marker) =>
+ val idx = str.stripPrefix(s"$marker:").toInt
+ Some(emittedBuffer(idx))
+ case _ => None
+ }
+}
+
+object EmittedFirrtlCircuitAnnotation extends EmittedAnnotation[EmittedFirrtlCircuit]("emittedFirrtlCircuit")
+object EmittedVerilogCircuitAnnotation extends EmittedAnnotation[EmittedVerilogCircuit]("emittedVerilogCircuit")
+object EmittedCircuitAnnotation {
+ def apply(value: EmittedCircuit): Annotation = value match {
+ case firrtl: EmittedFirrtlCircuit => EmittedFirrtlCircuitAnnotation(firrtl)
+ case verilog: EmittedVerilogCircuit => EmittedVerilogCircuitAnnotation(verilog)
+ }
+ def unapply(a: Annotation): Option[EmittedCircuit] = a match {
+ case EmittedFirrtlCircuitAnnotation(x) => Some(x)
+ case EmittedVerilogCircuitAnnotation(x) => Some(x)
+ case _ => None
+ }
+}
+object EmittedFirrtlModuleAnnotation extends EmittedAnnotation[EmittedFirrtlModule]("emittedFirrtlModule")
+object EmittedVerilogModuleAnnotation extends EmittedAnnotation[EmittedVerilogModule]("emittedVerilogModule")
+object EmittedModuleAnnotation {
+ def apply(value: EmittedModule): Annotation = value match {
+ case firrtl: EmittedFirrtlModule => EmittedFirrtlModuleAnnotation(firrtl)
+ case verilog: EmittedVerilogModule => EmittedVerilogModuleAnnotation(verilog)
+ }
+ def unapply(a: Annotation): Option[EmittedModule] = a match {
+ case EmittedFirrtlModuleAnnotation(x) => Some(x)
+ case EmittedVerilogModuleAnnotation(x) => Some(x)
+ case _ => None
+ }
+}
+
+
+sealed abstract class FirrtlEmitter(form: CircuitForm) extends Transform with Emitter {
+ def inputForm = form
+ def outputForm = form
+
+ private def emitAllModules(circuit: Circuit): Seq[EmittedFirrtlModule] = {
+ // For a given module, returns a Seq of all modules instantited inside of it
+ def collectInstantiatedModules(mod: Module, map: Map[String, DefModule]): Seq[DefModule] = {
+ // Use list instead of set to maintain order
+ val modules = mutable.ArrayBuffer.empty[DefModule]
+ def onStmt(stmt: Statement): Statement = stmt match {
+ case DefInstance(_, _, name) =>
+ modules += map(name)
+ stmt
+ case WDefInstance(_, _, name, _) =>
+ modules += map(name)
+ stmt
+ case _: WDefInstanceConnector => throwInternalError
+ case other => other map onStmt
+ }
+ onStmt(mod.body)
+ modules.distinct
+ }
+ val modMap = circuit.modules.map(m => m.name -> m).toMap
+ // Turn each module into it's own circuit with it as the top and all instantied modules as ExtModules
+ circuit.modules collect { case m: Module =>
+ val instModules = collectInstantiatedModules(m, modMap)
+ val extModules = instModules map {
+ case Module(info, name, ports, _) => ExtModule(info, name, ports, name, Seq.empty)
+ case ext: ExtModule => ext
+ }
+ val newCircuit = Circuit(m.info, extModules :+ m, m.name)
+ EmittedFirrtlModule(m.name, newCircuit.serialize)
+ }
+ }
+
+ def execute(state: CircuitState): CircuitState = {
+ val newAnnos = getMyAnnotations(state).flatMap {
+ case EmitCircuitAnnotation() =>
+ Seq(EmittedFirrtlCircuitAnnotation.apply(
+ EmittedFirrtlCircuit(state.circuit.main, state.circuit.serialize)))
+ case EmitAllModulesAnnotation() =>
+ emitAllModules(state.circuit) map (EmittedFirrtlModuleAnnotation(_))
+ case _ => Seq()
+ }
+ state.copy(annotations = Some(AnnotationMap(newAnnos)))
+ }
+
+ // Old style, deprecated
def emit(state: CircuitState, writer: Writer): Unit = writer.write(state.circuit.serialize)
}
+// ***** Start actual Emitters *****
+class HighFirrtlEmitter extends FirrtlEmitter(HighForm)
+class MiddleFirrtlEmitter extends FirrtlEmitter(HighForm)
+class LowFirrtlEmitter extends FirrtlEmitter(HighForm)
+
case class VRandom(width: BigInt) extends Expression {
def tpe = UIntType(IntWidth(width))
def nWords = (width + 31) / 32
@@ -36,7 +170,10 @@ case class VRandom(width: BigInt) extends Expression {
def mapWidth(f: Width => Width): Expression = this
}
-class VerilogEmitter extends Emitter with PassBased {
+class VerilogEmitter extends Transform with PassBased with Emitter {
+ def inputForm = LowForm
+ def outputForm = LowForm
+
val tab = " "
def AND(e1: WrappedExpression, e2: WrappedExpression): Expression = {
if (e1 == e2) e1.e1
@@ -583,21 +720,22 @@ class VerilogEmitter extends Emitter with PassBased {
m
}
- def emit_preamble(implicit w: Writer) {
- emit(Seq(
- "`ifdef RANDOMIZE_GARBAGE_ASSIGN\n",
- "`define RANDOMIZE\n",
- "`endif\n",
- "`ifdef RANDOMIZE_INVALID_ASSIGN\n",
- "`define RANDOMIZE\n",
- "`endif\n",
- "`ifdef RANDOMIZE_REG_INIT\n",
- "`define RANDOMIZE\n",
- "`endif\n",
- "`ifdef RANDOMIZE_MEM_INIT\n",
- "`define RANDOMIZE\n",
- "`endif\n"))
- }
+ /** Preamble for every emitted Verilog file */
+ def preamble: String =
+ """|`ifdef RANDOMIZE_GARBAGE_ASSIGN
+ |`define RANDOMIZE
+ |`endif
+ |`ifdef RANDOMIZE_INVALID_ASSIGN
+ |`define RANDOMIZE
+ |`endif
+ |`ifdef RANDOMIZE_REG_INIT
+ |`define RANDOMIZE
+ |`endif
+ |`ifdef RANDOMIZE_MEM_INIT
+ |`define RANDOMIZE
+ |`endif
+ |
+ |""".stripMargin
def passSeq = Seq(
passes.VerilogModulusCleanup,
@@ -606,12 +744,37 @@ class VerilogEmitter extends Emitter with PassBased {
passes.VerilogPrep)
def emit(state: CircuitState, writer: Writer): Unit = {
+ writer.write(preamble)
+
val circuit = runPasses(state.circuit)
- emit_preamble(writer)
- val moduleMap = (circuit.modules map (m => m.name -> m)).toMap
- circuit.modules foreach {
- case (m: Module) => emit_verilog(m, moduleMap)(writer)
- case (m: ExtModule) =>
+ val moduleMap = circuit.modules.map(m => m.name -> m).toMap
+ circuit.modules.foreach {
+ case m: Module => emit_verilog(m, moduleMap)(writer)
+ case _: ExtModule => // do nothing
+ }
+ }
+
+ def execute(state: CircuitState): CircuitState = {
+ val newAnnos = getMyAnnotations(state).flatMap {
+ case EmitCircuitAnnotation() =>
+ val writer = new java.io.StringWriter
+ emit(state, writer)
+ Seq(EmittedVerilogCircuitAnnotation(EmittedVerilogCircuit(state.circuit.main, writer.toString)))
+
+ case EmitAllModulesAnnotation() =>
+ val circuit = runPasses(state.circuit)
+ val moduleMap = circuit.modules.map(m => m.name -> m).toMap
+
+ circuit.modules flatMap {
+ case module: Module =>
+ val writer = new java.io.StringWriter
+ writer.write(preamble)
+ emit_verilog(module, moduleMap)(writer)
+ Some(EmittedVerilogModuleAnnotation(EmittedVerilogModule(module.name, writer.toString)))
+ case _: ExtModule => None
+ }
+ case _ => Seq()
}
+ state.copy(annotations = Some(AnnotationMap(newAnnos)))
}
}
diff --git a/src/main/scala/firrtl/ExecutionOptionsManager.scala b/src/main/scala/firrtl/ExecutionOptionsManager.scala
index 5615da99..2d221e6b 100644
--- a/src/main/scala/firrtl/ExecutionOptionsManager.scala
+++ b/src/main/scala/firrtl/ExecutionOptionsManager.scala
@@ -125,6 +125,15 @@ trait HasCommonOptions {
parser.help("help").text("prints this usage text")
}
+/** Firrtl output configuration specified by [[FirrtlExecutionOptions]]
+ *
+ * Derived from the fields of the execution options
+ * @see [[FirrtlExecutionOptions.getOutputConfig]]
+ */
+sealed abstract class OutputConfig
+final case class SingleFile(targetFile: String) extends OutputConfig
+final case class OneFilePerModule(targetDir: String) extends OutputConfig
+
/**
* The options that firrtl supports in callable component sense
*
@@ -133,7 +142,6 @@ trait HasCommonOptions {
* @param compilerName which compiler to use
* @param annotations annotations to pass to compiler
*/
-
case class FirrtlExecutionOptions(
inputFileNameOverride: String = "",
outputFileNameOverride: String = "",
@@ -144,9 +152,13 @@ case class FirrtlExecutionOptions(
customTransforms: Seq[Transform] = List.empty,
annotations: List[Annotation] = List.empty,
annotationFileNameOverride: String = "",
- forceAppendAnnoFile: Boolean = false)
+ forceAppendAnnoFile: Boolean = false,
+ emitOneFilePerModule: Boolean = false)
extends ComposableOptions {
+ require(!(emitOneFilePerModule && outputFileNameOverride.nonEmpty),
+ "Cannot both specify the output filename and emit one file per module!!!")
+
def infoMode: InfoMode = {
infoModeName match {
case "use" => UseInfo
@@ -186,14 +198,43 @@ case class FirrtlExecutionOptions(
def getInputFileName(optionsManager: ExecutionOptionsManager): String = {
optionsManager.getBuildFileName("fir", inputFileNameOverride)
}
- /**
- * build the output file name, taking overriding parameters
+ /** Get the user-specified [[OutputConfig]]
*
* @param optionsManager this is needed to access build function and its common options
- * @return
+ * @return the output configuration
+ */
+ def getOutputConfig(optionsManager: ExecutionOptionsManager): OutputConfig = {
+ if (emitOneFilePerModule) OneFilePerModule(optionsManager.targetDirName)
+ else SingleFile(optionsManager.getBuildFileName(outputSuffix, outputFileNameOverride))
+ }
+ /** Get the user-specified targetFile assuming [[OutputConfig]] is [[SingleFile]]
+ *
+ * @param optionsManager this is needed to access build function and its common options
+ * @return the targetFile as a String
*/
- def getOutputFileName(optionsManager: ExecutionOptionsManager): String = {
- optionsManager.getBuildFileName(outputSuffix, outputFileNameOverride)
+ def getTargetFile(optionsManager: ExecutionOptionsManager): String = {
+ getOutputConfig(optionsManager) match {
+ case SingleFile(targetFile) => targetFile
+ case other => throw new Exception("OutputConfig is not SingleFile!")
+ }
+ }
+ /** Gives annotations based on the output configuration
+ *
+ * @param optionsManager this is needed to access build function and its common options
+ * @return Annotations that will be consumed by emitter Transforms
+ */
+ def getEmitterAnnos(optionsManager: ExecutionOptionsManager): Seq[Annotation] = {
+ // TODO should this be a public function?
+ val emitter = compilerName match {
+ case "high" => classOf[HighFirrtlEmitter]
+ case "middle" => classOf[MiddleFirrtlEmitter]
+ case "low" => classOf[LowFirrtlEmitter]
+ case "verilog" => classOf[VerilogEmitter]
+ }
+ getOutputConfig(optionsManager) match {
+ case SingleFile(_) => Seq(EmitCircuitAnnotation(emitter))
+ case OneFilePerModule(_) => Seq(EmitAllModulesAnnotation(emitter))
+ }
}
/**
* build the annotation file name, taking overriding parameters
@@ -223,8 +264,13 @@ trait HasFirrtlOptions {
parser.opt[String]("output-file")
.abbr("o")
- .valueName ("<output>").
- foreach { x =>
+ .valueName("<output>")
+ .validate { x =>
+ if (firrtlOptions.emitOneFilePerModule)
+ parser.failure("Cannot override output-file if split-modules is specified")
+ else parser.success
+ }
+ .foreach { x =>
firrtlOptions = firrtlOptions.copy(outputFileNameOverride = x)
}.text {
"use this to override the default output file name, default is empty"
@@ -234,7 +280,7 @@ trait HasFirrtlOptions {
.abbr("faf")
.valueName ("<output>").
foreach { x =>
- firrtlOptions = firrtlOptions.copy(outputFileNameOverride = x)
+ firrtlOptions = firrtlOptions.copy(annotationFileNameOverride = x)
}.text {
"use this to override the default annotation file name, default is empty"
}
@@ -334,8 +380,20 @@ trait HasFirrtlOptions {
"List which signal drives each clock of every descendent of specified module"
}
- parser.note("")
+ parser.opt[Unit]("split-modules")
+ .abbr("fsm")
+ .validate { x =>
+ if (firrtlOptions.outputFileNameOverride.nonEmpty)
+ parser.failure("Cannot split-modules if output-file is specified")
+ else parser.success
+ }
+ .foreach { _ =>
+ firrtlOptions = firrtlOptions.copy(emitOneFilePerModule = true)
+ }.text {
+ "Emit each module to its own file in the target directory."
+ }
+ parser.note("")
}
sealed trait FirrtlExecutionResult
@@ -345,7 +403,7 @@ sealed trait FirrtlExecutionResult
* the type of compile
*
* @param emitType The name of the compiler used, currently "high", "middle", "low", or "verilog"
- * @param emitted The text result of the compilation, could be verilog or firrtl text.
+ * @param emitted The emitted result of compilation
*/
case class FirrtlExecutionSuccess(emitType: String, emitted: String) extends FirrtlExecutionResult
diff --git a/src/main/scala/firrtl/LoweringCompilers.scala b/src/main/scala/firrtl/LoweringCompilers.scala
index 1a4b24cd..ab9f6ea4 100644
--- a/src/main/scala/firrtl/LoweringCompilers.scala
+++ b/src/main/scala/firrtl/LoweringCompilers.scala
@@ -116,25 +116,25 @@ import firrtl.transforms.BlackBoxSourceHelper
* Will replace Chirrtl constructs with Firrtl
*/
class HighFirrtlCompiler extends Compiler {
- def emitter = new FirrtlEmitter
+ def emitter = new HighFirrtlEmitter
def transforms: Seq[Transform] = getLoweringTransforms(ChirrtlForm, HighForm)
}
/** Emits middle Firrtl input circuit */
class MiddleFirrtlCompiler extends Compiler {
- def emitter = new FirrtlEmitter
+ def emitter = new MiddleFirrtlEmitter
def transforms: Seq[Transform] = getLoweringTransforms(ChirrtlForm, MidForm)
}
/** Emits lowered input circuit */
class LowFirrtlCompiler extends Compiler {
- def emitter = new FirrtlEmitter
+ def emitter = new LowFirrtlEmitter
def transforms: Seq[Transform] = getLoweringTransforms(ChirrtlForm, LowForm)
}
/** Emits Verilog */
class VerilogCompiler extends Compiler {
def emitter = new VerilogEmitter
- def transforms: Seq[Transform] =
- getLoweringTransforms(ChirrtlForm, LowForm) ++ Seq(new LowFirrtlOptimization, new BlackBoxSourceHelper)
+ def transforms: Seq[Transform] = getLoweringTransforms(ChirrtlForm, LowForm) ++
+ Seq(new LowFirrtlOptimization, new BlackBoxSourceHelper)
}
diff --git a/src/main/scala/firrtl/annotations/Named.scala b/src/main/scala/firrtl/annotations/Named.scala
index 4b39c977..0e365249 100644
--- a/src/main/scala/firrtl/annotations/Named.scala
+++ b/src/main/scala/firrtl/annotations/Named.scala
@@ -14,6 +14,12 @@ sealed trait Named {
def serialize: String
}
+/** Name referring to the top of the circuit */
+final case object CircuitTopName extends Named {
+ def name: String = "CircuitTop"
+ def serialize: String = name
+}
+
final case class CircuitName(name: String) extends Named {
if(!validModuleName(name)) throw AnnotationException(s"Illegal circuit name: $name")
def serialize: String = name