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/scala/firrtl/Emitter.scala | |
| 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/scala/firrtl/Emitter.scala')
| -rw-r--r-- | src/main/scala/firrtl/Emitter.scala | 207 |
1 files changed, 185 insertions, 22 deletions
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))) } } |
