aboutsummaryrefslogtreecommitdiff
path: root/src/main/scala/firrtl/Emitter.scala
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/scala/firrtl/Emitter.scala')
-rw-r--r--src/main/scala/firrtl/Emitter.scala207
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)))
}
}