diff options
| author | Jack Koenig | 2017-03-06 14:51:20 -0600 |
|---|---|---|
| committer | GitHub | 2017-03-06 14:51:20 -0600 |
| commit | 3d58123ae654a2101ba81304ca3863b3be12c4f3 (patch) | |
| tree | 2e662485fef5327a2697dbd4a9b42a2cdc5bae5f /src/main | |
| parent | c89f74f19dd5162ee533a0a20825819bc52bc73e (diff) | |
Add ability to emit 1 file per module (#443)
Changes Emitters to also be Transforms and use Annotations for both
telling an emitter to do emission as well as getting the emitted result.
Helper functions ease the use of the new interface. Also adds a
FirrtlExecutionOptions field as well as a command-line option. Use of
Writers in Compilers and Emitters is now deprecated.
Diffstat (limited to 'src/main')
| -rw-r--r-- | src/main/scala/firrtl/Compiler.scala | 87 | ||||
| -rw-r--r-- | src/main/scala/firrtl/Driver.scala | 46 | ||||
| -rw-r--r-- | src/main/scala/firrtl/Emitter.scala | 207 | ||||
| -rw-r--r-- | src/main/scala/firrtl/ExecutionOptionsManager.scala | 82 | ||||
| -rw-r--r-- | src/main/scala/firrtl/LoweringCompilers.scala | 10 | ||||
| -rw-r--r-- | src/main/scala/firrtl/annotations/Named.scala | 6 |
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 |
