diff options
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))) } } |
