aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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
-rw-r--r--src/test/scala/firrtlTests/AnnotationTests.scala15
-rw-r--r--src/test/scala/firrtlTests/AttachSpec.scala8
-rw-r--r--src/test/scala/firrtlTests/CInferMDirSpec.scala5
-rw-r--r--src/test/scala/firrtlTests/ChirrtlMemSpec.scala10
-rw-r--r--src/test/scala/firrtlTests/CompilerTests.scala9
-rw-r--r--src/test/scala/firrtlTests/ConstantPropagationTests.scala1
-rw-r--r--src/test/scala/firrtlTests/DriverSpec.scala68
-rw-r--r--src/test/scala/firrtlTests/FirrtlSpec.scala38
-rw-r--r--src/test/scala/firrtlTests/InferReadWriteSpec.scala9
-rw-r--r--src/test/scala/firrtlTests/InlineInstancesTests.scala29
-rw-r--r--src/test/scala/firrtlTests/IntegrationSpec.scala38
-rw-r--r--src/test/scala/firrtlTests/MultiThreadingSpec.scala5
-rw-r--r--src/test/scala/firrtlTests/PassTests.scala37
-rw-r--r--src/test/scala/firrtlTests/ReplSeqMemTests.scala36
-rw-r--r--src/test/scala/firrtlTests/UnitTests.scala8
-rw-r--r--src/test/scala/firrtlTests/VerilogEmitterTests.scala8
-rw-r--r--src/test/scala/firrtlTests/fixed/FixedPointMathSpec.scala8
-rw-r--r--src/test/scala/firrtlTests/fixed/FixedTypeInferenceSpec.scala8
-rw-r--r--src/test/scala/firrtlTests/transforms/BlacklBoxSourceHelperSpec.scala5
-rw-r--r--src/test/scala/firrtlTests/transforms/DedupTests.scala14
26 files changed, 555 insertions, 242 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
diff --git a/src/test/scala/firrtlTests/AnnotationTests.scala b/src/test/scala/firrtlTests/AnnotationTests.scala
index 8acada93..29f8f51a 100644
--- a/src/test/scala/firrtlTests/AnnotationTests.scala
+++ b/src/test/scala/firrtlTests/AnnotationTests.scala
@@ -2,7 +2,7 @@
package firrtlTests
-import java.io.{File, FileWriter, StringWriter, Writer}
+import java.io.{File, FileWriter, Writer}
import firrtl.annotations.AnnotationYamlProtocol._
import firrtl.annotations._
@@ -20,14 +20,14 @@ trait AnnotationSpec extends LowTransformSpec {
def transform = new CustomResolveAndCheck(LowForm)
// Check if Annotation Exception is thrown
- override def failingexecute(writer: Writer, annotations: AnnotationMap, input: String): Exception = {
+ override def failingexecute(annotations: AnnotationMap, input: String): Exception = {
intercept[AnnotationException] {
- compile(CircuitState(parse(input), ChirrtlForm, Some(annotations)), writer)
+ compile(CircuitState(parse(input), ChirrtlForm, Some(annotations)), Seq.empty)
}
}
- def execute(writer: Writer, annotations: AnnotationMap, input: String, check: Annotation): Unit = {
- val cr = compile(CircuitState(parse(input), ChirrtlForm, Some(annotations)), writer)
- cr.annotations.get.annotations should be (Seq(check))
+ def execute(annotations: AnnotationMap, input: String, check: Annotation): Unit = {
+ val cr = compile(CircuitState(parse(input), ChirrtlForm, Some(annotations)), Seq.empty)
+ cr.annotations.get.annotations should contain (check)
}
}
@@ -53,9 +53,8 @@ class AnnotationTests extends AnnotationSpec with Matchers {
val cName = ComponentName("c", mName)
"Loose and Sticky annotation on a node" should "pass through" in {
- val w = new StringWriter()
val ta = Annotation(cName, classOf[Transform], "")
- execute(w, getAMap(ta), input, ta)
+ execute(getAMap(ta), input, ta)
}
"Annotations" should "be readable from file" in {
diff --git a/src/test/scala/firrtlTests/AttachSpec.scala b/src/test/scala/firrtlTests/AttachSpec.scala
index 5eed33bd..c29a7e43 100644
--- a/src/test/scala/firrtlTests/AttachSpec.scala
+++ b/src/test/scala/firrtlTests/AttachSpec.scala
@@ -12,14 +12,6 @@ import firrtl.passes._
import firrtl.Parser.IgnoreInfo
class InoutVerilogSpec extends FirrtlFlatSpec {
- private def executeTest(input: String, expected: Seq[String], compiler: Compiler) = {
- val writer = new StringWriter()
- compiler.compile(CircuitState(parse(input), ChirrtlForm), writer)
- val lines = writer.toString().split("\n") map normalized
- expected foreach { e =>
- lines should contain(e)
- }
- }
behavior of "Analog"
diff --git a/src/test/scala/firrtlTests/CInferMDirSpec.scala b/src/test/scala/firrtlTests/CInferMDirSpec.scala
index 3721543b..773a0bf3 100644
--- a/src/test/scala/firrtlTests/CInferMDirSpec.scala
+++ b/src/test/scala/firrtlTests/CInferMDirSpec.scala
@@ -70,9 +70,8 @@ circuit foo :
""".stripMargin
val annotationMap = AnnotationMap(Nil)
- val writer = new java.io.StringWriter
- compile(CircuitState(parse(input), ChirrtlForm, Some(annotationMap)), writer)
+ val res = compileAndEmit(CircuitState(parse(input), ChirrtlForm, Some(annotationMap)))
// Check correctness of firrtl
- parse(writer.toString)
+ parse(res.getEmittedCircuit.value)
}
}
diff --git a/src/test/scala/firrtlTests/ChirrtlMemSpec.scala b/src/test/scala/firrtlTests/ChirrtlMemSpec.scala
index 2bbe46c8..fd984661 100644
--- a/src/test/scala/firrtlTests/ChirrtlMemSpec.scala
+++ b/src/test/scala/firrtlTests/ChirrtlMemSpec.scala
@@ -77,10 +77,9 @@ circuit foo :
""".stripMargin
val annotationMap = AnnotationMap(Nil)
- val writer = new java.io.StringWriter
- compile(CircuitState(parse(input), ChirrtlForm, Some(annotationMap)), writer)
+ val res = compileAndEmit(CircuitState(parse(input), ChirrtlForm, Some(annotationMap)))
// Check correctness of firrtl
- parse(writer.toString)
+ parse(res.getEmittedCircuit.value)
}
"Combinational Memory" should "have correct enable signals" in {
@@ -104,9 +103,8 @@ circuit foo :
""".stripMargin
val annotationMap = AnnotationMap(Nil)
- val writer = new java.io.StringWriter
- compile(CircuitState(parse(input), ChirrtlForm, Some(annotationMap)), writer)
+ val res = compileAndEmit(CircuitState(parse(input), ChirrtlForm, Some(annotationMap)))
// Check correctness of firrtl
- parse(writer.toString)
+ parse(res.getEmittedCircuit.value)
}
}
diff --git a/src/test/scala/firrtlTests/CompilerTests.scala b/src/test/scala/firrtlTests/CompilerTests.scala
index a9fce0c2..39d54755 100644
--- a/src/test/scala/firrtlTests/CompilerTests.scala
+++ b/src/test/scala/firrtlTests/CompilerTests.scala
@@ -2,8 +2,6 @@
package firrtlTests
-import java.io.StringWriter
-
import org.scalatest.FlatSpec
import org.scalatest.Matchers
import org.scalatest.junit.JUnitRunner
@@ -29,13 +27,12 @@ import firrtl.{
*/
abstract class CompilerSpec extends FlatSpec {
def parse (s: String): Circuit = Parser.parse(s.split("\n").toIterator)
- val writer = new StringWriter()
def compiler: Compiler
def input: String
def check: String
def getOutput: String = {
- compiler.compile(CircuitState(parse(input), ChirrtlForm), writer)
- writer.toString()
+ val res = compiler.compileAndEmit(CircuitState(parse(input), ChirrtlForm))
+ res.getEmittedCircuit.value
}
}
@@ -170,6 +167,6 @@ circuit Top :
"endmodule\n"
).reduce(_ + "\n" + _)
"A circuit's verilog output" should "match the given string" in {
- (getOutput) should be (check)
+ getOutput should be (check)
}
}
diff --git a/src/test/scala/firrtlTests/ConstantPropagationTests.scala b/src/test/scala/firrtlTests/ConstantPropagationTests.scala
index 4506f4ec..95785717 100644
--- a/src/test/scala/firrtlTests/ConstantPropagationTests.scala
+++ b/src/test/scala/firrtlTests/ConstantPropagationTests.scala
@@ -3,7 +3,6 @@
package firrtlTests
import org.scalatest.Matchers
-import java.io.{StringWriter,Writer}
import firrtl.ir.Circuit
import firrtl.Parser.IgnoreInfo
import firrtl.Parser
diff --git a/src/test/scala/firrtlTests/DriverSpec.scala b/src/test/scala/firrtlTests/DriverSpec.scala
index 4e1add39..9cbeb6f9 100644
--- a/src/test/scala/firrtlTests/DriverSpec.scala
+++ b/src/test/scala/firrtlTests/DriverSpec.scala
@@ -66,7 +66,7 @@ class DriverSpec extends FreeSpec with Matchers with BackendCompilationUtilities
val firrtlOptions = optionsManager.firrtlOptions
val inputFileName = optionsManager.getBuildFileName("fir", firrtlOptions.inputFileNameOverride)
inputFileName should be ("./cat.fir")
- val outputFileName = optionsManager.getBuildFileName("v", firrtlOptions.outputFileNameOverride)
+ val outputFileName = firrtlOptions.getTargetFile(optionsManager)
outputFileName should be ("./cat.v")
}
"input and output file names can be overridden, overrides do not use targetDir" in {
@@ -79,7 +79,7 @@ class DriverSpec extends FreeSpec with Matchers with BackendCompilationUtilities
val firrtlOptions = optionsManager.firrtlOptions
val inputFileName = optionsManager.getBuildFileName("fir", firrtlOptions.inputFileNameOverride)
inputFileName should be ("./bob.fir")
- val outputFileName = optionsManager.getBuildFileName("v", firrtlOptions.outputFileNameOverride)
+ val outputFileName = firrtlOptions.getTargetFile(optionsManager)
outputFileName should be ("carol.v")
}
"various annotations can be created from command line, currently:" - {
@@ -142,26 +142,31 @@ class DriverSpec extends FreeSpec with Matchers with BackendCompilationUtilities
annotationsTestFile.delete()
}
- val input =
- """
- |circuit Dummy :
- | module Dummy :
- | input x : UInt<1>
- | output y : UInt<1>
- | y <= x
- """.stripMargin
-
- "Driver produces files with different names depending on the compiler" - {
- "compiler changes the default name of the output file" in {
-
+ "Circuits are emitted on properly" - {
+ val input =
+ """|circuit Top :
+ | module Top :
+ | output foo : UInt<32>
+ | inst c of Child
+ | inst e of External
+ | foo <= tail(add(c.foo, e.foo), 1)
+ | module Child :
+ | output foo : UInt<32>
+ | inst e of External
+ | foo <= e.foo
+ | extmodule External :
+ | output foo : UInt<32>
+ """.stripMargin
+
+ "To a single file with file extension depending on the compiler by default" in {
Seq(
- "low" -> "./Dummy.lo.fir",
- "high" -> "./Dummy.hi.fir",
- "middle" -> "./Dummy.mid.fir",
- "verilog" -> "./Dummy.v"
+ "low" -> "./Top.lo.fir",
+ "high" -> "./Top.hi.fir",
+ "middle" -> "./Top.mid.fir",
+ "verilog" -> "./Top.v"
).foreach { case (compilerName, expectedOutputFileName) =>
val manager = new ExecutionOptionsManager("test") with HasFirrtlOptions {
- commonOptions = CommonOptions(topName = "Dummy")
+ commonOptions = CommonOptions(topName = "Top")
firrtlOptions = FirrtlExecutionOptions(firrtlSource = Some(input), compilerName = compilerName)
}
@@ -172,8 +177,33 @@ class DriverSpec extends FreeSpec with Matchers with BackendCompilationUtilities
file.delete()
}
}
+ "To a single file per module if OneFilePerModule is specified" in {
+ Seq(
+ "low" -> Seq("./Top.lo.fir", "./Child.lo.fir"),
+ "high" -> Seq("./Top.hi.fir", "./Child.hi.fir"),
+ "middle" -> Seq("./Top.mid.fir", "./Child.mid.fir"),
+ "verilog" -> Seq("./Top.v", "./Child.v")
+ ).foreach { case (compilerName, expectedOutputFileNames) =>
+ println(s"$compilerName -> $expectedOutputFileNames")
+ val manager = new ExecutionOptionsManager("test") with HasFirrtlOptions {
+ commonOptions = CommonOptions(topName = "Top")
+ firrtlOptions = FirrtlExecutionOptions(firrtlSource = Some(input),
+ compilerName = compilerName,
+ emitOneFilePerModule = true)
+ }
+
+ firrtl.Driver.execute(manager)
+
+ for (name <- expectedOutputFileNames) {
+ val file = new File(name)
+ file.exists() should be (true)
+ file.delete()
+ }
+ }
+ }
}
+
"Directory deleter is handy for cleaning up after tests" - {
"for example making a directory tree, and deleting it looks like" in {
FileUtils.makeDirectory("dog/fox/wolf")
diff --git a/src/test/scala/firrtlTests/FirrtlSpec.scala b/src/test/scala/firrtlTests/FirrtlSpec.scala
index 7dd439e4..6bf73a80 100644
--- a/src/test/scala/firrtlTests/FirrtlSpec.scala
+++ b/src/test/scala/firrtlTests/FirrtlSpec.scala
@@ -16,15 +16,13 @@ import firrtl.annotations
import firrtl.util.BackendCompilationUtilities
trait FirrtlRunners extends BackendCompilationUtilities {
- def parse(str: String) = Parser.parse(str.split("\n").toIterator, IgnoreInfo)
lazy val cppHarness = new File(s"/top.cpp")
/** Compiles input Firrtl to Verilog */
def compileToVerilog(input: String, annotations: AnnotationMap = AnnotationMap(Seq.empty)): String = {
val circuit = Parser.parse(input.split("\n").toIterator)
val compiler = new VerilogCompiler
- val writer = new java.io.StringWriter
- compiler.compile(CircuitState(circuit, HighForm, Some(annotations)), writer)
- writer.toString
+ val res = compiler.compileAndEmit(CircuitState(circuit, HighForm, Some(annotations)))
+ res.getEmittedCircuit.value
}
/** Compile a Firrtl file
*
@@ -40,13 +38,15 @@ trait FirrtlRunners extends BackendCompilationUtilities {
val testDir = createTestDirectory(prefix)
copyResourceToFile(s"${srcDir}/${prefix}.fir", new File(testDir, s"${prefix}.fir"))
- Driver.compile(
- s"$testDir/$prefix.fir",
- s"$testDir/$prefix.v",
- new VerilogCompiler(),
- Parser.IgnoreInfo,
- customTransforms,
- annotations)
+ val optionsManager = new ExecutionOptionsManager(prefix) with HasFirrtlOptions {
+ commonOptions = CommonOptions(topName = prefix, targetDirName = testDir.getPath)
+ firrtlOptions = FirrtlExecutionOptions(
+ infoModeName = "ignore",
+ customTransforms = customTransforms,
+ annotations = annotations.annotations.toList)
+ }
+ firrtl.Driver.execute(optionsManager)
+
testDir
}
/** Execute a Firrtl Test
@@ -79,7 +79,7 @@ trait FirrtlRunners extends BackendCompilationUtilities {
}
}
-trait FirrtlMatchers {
+trait FirrtlMatchers extends Matchers {
// Replace all whitespace with a single space and remove leading and
// trailing whitespace
// Note this is intended for single-line strings, no newlines
@@ -87,11 +87,23 @@ trait FirrtlMatchers {
require(!s.contains("\n"))
s.replaceAll("\\s+", " ").trim
}
+ def parse(str: String) = Parser.parse(str.split("\n").toIterator, IgnoreInfo)
+ /** Helper for executing tests
+ * compiler will be run on input then emitted result will each be split into
+ * lines and normalized.
+ */
+ def executeTest(input: String, expected: Seq[String], compiler: Compiler) = {
+ val finalState = compiler.compileAndEmit(CircuitState(parse(input), ChirrtlForm))
+ val lines = finalState.getEmittedCircuit.value split "\n" map normalized
+ for (e <- expected) {
+ lines should contain (e)
+ }
+ }
}
abstract class FirrtlPropSpec extends PropSpec with PropertyChecks with FirrtlRunners with LazyLogging
-abstract class FirrtlFlatSpec extends FlatSpec with Matchers with FirrtlRunners with FirrtlMatchers with LazyLogging
+abstract class FirrtlFlatSpec extends FlatSpec with FirrtlRunners with FirrtlMatchers with LazyLogging
/** Super class for execution driven Firrtl tests */
abstract class ExecutionTest(name: String, dir: String, vFiles: Seq[String] = Seq.empty) extends FirrtlPropSpec {
diff --git a/src/test/scala/firrtlTests/InferReadWriteSpec.scala b/src/test/scala/firrtlTests/InferReadWriteSpec.scala
index a5eea147..91dc911c 100644
--- a/src/test/scala/firrtlTests/InferReadWriteSpec.scala
+++ b/src/test/scala/firrtlTests/InferReadWriteSpec.scala
@@ -42,6 +42,7 @@ class InferReadWriteSpec extends SimpleTransformSpec {
def passSeq = Seq(InferReadWriteCheckPass)
}
+ def emitter = new MiddleFirrtlEmitter
def transforms = Seq(
new ChirrtlToHighFirrtl,
new IRToWorkingIR,
@@ -76,10 +77,9 @@ circuit sram6t :
""".stripMargin
val annotationMap = AnnotationMap(Seq(memlib.InferReadWriteAnnotation("sram6t")))
- val writer = new java.io.StringWriter
- compile(CircuitState(parse(input), ChirrtlForm, Some(annotationMap)), writer)
+ val res = compileAndEmit(CircuitState(parse(input), ChirrtlForm, Some(annotationMap)))
// Check correctness of firrtl
- parse(writer.toString)
+ parse(res.getEmittedCircuit.value)
}
"Infer ReadWrite Ports" should "not infer readwrite ports for the difference clocks" in {
@@ -108,9 +108,8 @@ circuit sram6t :
""".stripMargin
val annotationMap = AnnotationMap(Seq(memlib.InferReadWriteAnnotation("sram6t")))
- val writer = new java.io.StringWriter
intercept[InferReadWriteCheckException] {
- compile(CircuitState(parse(input), ChirrtlForm, Some(annotationMap)), writer)
+ compileAndEmit(CircuitState(parse(input), ChirrtlForm, Some(annotationMap)))
}
}
}
diff --git a/src/test/scala/firrtlTests/InlineInstancesTests.scala b/src/test/scala/firrtlTests/InlineInstancesTests.scala
index 89862145..25a194d4 100644
--- a/src/test/scala/firrtlTests/InlineInstancesTests.scala
+++ b/src/test/scala/firrtlTests/InlineInstancesTests.scala
@@ -2,8 +2,6 @@
package firrtlTests
-import java.io.StringWriter
-
import org.scalatest.FlatSpec
import org.scalatest.Matchers
import org.scalatest.junit.JUnitRunner
@@ -49,9 +47,8 @@ class InlineInstancesTests extends LowTransformSpec {
| i$b <= i$a
| b <= i$b
| i$a <= a""".stripMargin
- val writer = new StringWriter()
val aMap = new AnnotationMap(Seq(InlineAnnotation(ModuleName("Inline", CircuitName("Top")))))
- execute(writer, aMap, input, check)
+ execute(aMap, input, check)
}
"The all instances of Simple" should "be inlined" in {
@@ -83,9 +80,8 @@ class InlineInstancesTests extends LowTransformSpec {
| b <= i1$b
| i0$a <= a
| i1$a <= i0$b""".stripMargin
- val writer = new StringWriter()
val aMap = new AnnotationMap(Seq(InlineAnnotation(ModuleName("Simple", CircuitName("Top")))))
- execute(writer, aMap, input, check)
+ execute(aMap, input, check)
}
"Only one instance of Simple" should "be inlined" in {
@@ -119,9 +115,8 @@ class InlineInstancesTests extends LowTransformSpec {
| input a : UInt<32>
| output b : UInt<32>
| b <= a""".stripMargin
- val writer = new StringWriter()
val aMap = new AnnotationMap(Seq(InlineAnnotation(ComponentName("i0",ModuleName("Top", CircuitName("Top"))))))
- execute(writer, aMap, input, check)
+ execute(aMap, input, check)
}
"All instances of A" should "be inlined" in {
@@ -165,9 +160,8 @@ class InlineInstancesTests extends LowTransformSpec {
| i$b <= i$a
| b <= i$b
| i$a <= a""".stripMargin
- val writer = new StringWriter()
val aMap = new AnnotationMap(Seq(InlineAnnotation(ModuleName("A", CircuitName("Top")))))
- execute(writer, aMap, input, check)
+ execute(aMap, input, check)
}
"Non-inlined instances" should "still prepend prefix" in {
@@ -205,9 +199,8 @@ class InlineInstancesTests extends LowTransformSpec {
| input a : UInt<32>
| output b : UInt<32>
| b <= a""".stripMargin
- val writer = new StringWriter()
val aMap = new AnnotationMap(Seq(InlineAnnotation(ModuleName("A", CircuitName("Top")))))
- execute(writer, aMap, input, check)
+ execute(aMap, input, check)
}
// ---- Errors ----
@@ -224,9 +217,8 @@ class InlineInstancesTests extends LowTransformSpec {
| extmodule A :
| input a : UInt<32>
| output b : UInt<32>""".stripMargin
- val writer = new StringWriter()
val aMap = new AnnotationMap(Seq(InlineAnnotation(ModuleName("A", CircuitName("Top")))))
- failingexecute(writer, aMap, input)
+ failingexecute(aMap, input)
}
// 2) ext instance
"External instance" should "not be inlined" in {
@@ -241,9 +233,8 @@ class InlineInstancesTests extends LowTransformSpec {
| extmodule A :
| input a : UInt<32>
| output b : UInt<32>""".stripMargin
- val writer = new StringWriter()
val aMap = new AnnotationMap(Seq(InlineAnnotation(ModuleName("A", CircuitName("Top")))))
- failingexecute(writer, aMap, input)
+ failingexecute(aMap, input)
}
// 3) no module
"Inlined module" should "exist" in {
@@ -253,9 +244,8 @@ class InlineInstancesTests extends LowTransformSpec {
| input a : UInt<32>
| output b : UInt<32>
| b <= a""".stripMargin
- val writer = new StringWriter()
val aMap = new AnnotationMap(Seq(InlineAnnotation(ModuleName("A", CircuitName("Top")))))
- failingexecute(writer, aMap, input)
+ failingexecute(aMap, input)
}
// 4) no inst
"Inlined instance" should "exist" in {
@@ -265,9 +255,8 @@ class InlineInstancesTests extends LowTransformSpec {
| input a : UInt<32>
| output b : UInt<32>
| b <= a""".stripMargin
- val writer = new StringWriter()
val aMap = new AnnotationMap(Seq(InlineAnnotation(ModuleName("A", CircuitName("Top")))))
- failingexecute(writer, aMap, input)
+ failingexecute(aMap, input)
}
}
diff --git a/src/test/scala/firrtlTests/IntegrationSpec.scala b/src/test/scala/firrtlTests/IntegrationSpec.scala
index 335922bd..52fbb611 100644
--- a/src/test/scala/firrtlTests/IntegrationSpec.scala
+++ b/src/test/scala/firrtlTests/IntegrationSpec.scala
@@ -2,13 +2,51 @@
package firrtlTests
+import firrtl._
import org.scalatest._
import org.scalatest.prop._
+import java.io.File
+
class GCDExecutionTest extends ExecutionTest("GCDTester", "/integration")
class RightShiftExecutionTest extends ExecutionTest("RightShiftTester", "/integration")
class MemExecutionTest extends ExecutionTest("MemTester", "/integration")
+// This is a bit custom some kind of one off
+class GCDSplitEmissionExecutionTest extends FirrtlFlatSpec {
+ "GCDTester" should "work even when the modules are emitted to different files" in {
+ val top = "GCDTester"
+ val testDir = createTestDirectory("GCDTesterSplitEmission")
+ val sourceFile = new File(testDir, s"$top.fir")
+ copyResourceToFile(s"/integration/$top.fir", sourceFile)
+
+ val optionsManager = new ExecutionOptionsManager("GCDTesterSplitEmission") with HasFirrtlOptions {
+ commonOptions = CommonOptions(topName = top, targetDirName = testDir.getPath)
+ firrtlOptions = FirrtlExecutionOptions(
+ inputFileNameOverride = sourceFile.getPath,
+ compilerName = "verilog",
+ infoModeName = "ignore",
+ emitOneFilePerModule = true)
+ }
+ firrtl.Driver.execute(optionsManager)
+
+ // expected filenames
+ val dutFile = new File(testDir, "DecoupledGCD.v")
+ val topFile = new File(testDir, s"$top.v")
+ dutFile should exist
+ topFile should exist
+
+ // Copy harness over
+ val harness = new File(testDir, s"top.cpp")
+ copyResourceToFile(cppHarness.toString, harness)
+
+ // topFile will be compiled by Verilator command by default but we need to also include dutFile
+ verilogToCpp(top, testDir, Seq(dutFile), harness).!
+ cppToExe(top, testDir).!
+ assert(executeExpectingSuccess(top, testDir))
+ }
+}
+
class RocketCompilationTest extends CompilationTest("rocket", "/regress")
class RocketFirrtlCompilationTest extends CompilationTest("rocket-firrtl", "/regress")
class BOOMRobCompilationTest extends CompilationTest("Rob", "/regress")
diff --git a/src/test/scala/firrtlTests/MultiThreadingSpec.scala b/src/test/scala/firrtlTests/MultiThreadingSpec.scala
index 1698c462..444faebc 100644
--- a/src/test/scala/firrtlTests/MultiThreadingSpec.scala
+++ b/src/test/scala/firrtlTests/MultiThreadingSpec.scala
@@ -13,10 +13,9 @@ class MultiThreadingSpec extends FirrtlPropSpec {
property("The FIRRTL compiler should be thread safe") {
// Run the compiler we're testing
def runCompiler(input: Seq[String], compiler: firrtl.Compiler): String = {
- val writer = new java.io.StringWriter
val parsedInput = firrtl.Parser.parse(input)
- compiler.compile(CircuitState(parsedInput, ChirrtlForm), writer)
- writer.toString
+ val res = compiler.compileAndEmit(CircuitState(parsedInput, ChirrtlForm))
+ res.getEmittedCircuit.value
}
// The parameters we're testing with
val compilers = Seq(
diff --git a/src/test/scala/firrtlTests/PassTests.scala b/src/test/scala/firrtlTests/PassTests.scala
index c417c4fb..df56c097 100644
--- a/src/test/scala/firrtlTests/PassTests.scala
+++ b/src/test/scala/firrtlTests/PassTests.scala
@@ -9,50 +9,28 @@ import org.scalatest.junit.JUnitRunner
import firrtl.ir.Circuit
import firrtl.Parser.UseInfo
import firrtl.passes.{Pass, PassExceptions, RemoveEmpty}
-import firrtl.{
- Transform,
- AnnotationMap,
- PassBasedTransform,
- CircuitState,
- CircuitForm,
- ChirrtlForm,
- HighForm,
- MidForm,
- LowForm,
- SimpleRun,
- ChirrtlToHighFirrtl,
- IRToWorkingIR,
- ResolveAndCheck,
- HighFirrtlToMiddleFirrtl,
- MiddleFirrtlToLowFirrtl,
- FirrtlEmitter,
- Compiler,
- Parser
-}
-
+import firrtl._
// An example methodology for testing Firrtl Passes
// Spec class should extend this class
abstract class SimpleTransformSpec extends FlatSpec with Matchers with Compiler with LazyLogging {
- def emitter = new FirrtlEmitter
-
// Utility function
def parse(s: String): Circuit = Parser.parse(s.split("\n").toIterator, infoMode = UseInfo)
def squash(c: Circuit): Circuit = RemoveEmpty.run(c)
// Executes the test. Call in tests.
- def execute(writer: Writer, annotations: AnnotationMap, input: String, check: String): Unit = {
- compile(CircuitState(parse(input), ChirrtlForm, Some(annotations)), writer)
- val actual = RemoveEmpty.run(parse(writer.toString)).serialize
+ def execute(annotations: AnnotationMap, input: String, check: String): Unit = {
+ val finalState = compileAndEmit(CircuitState(parse(input), ChirrtlForm, Some(annotations)))
+ val actual = RemoveEmpty.run(parse(finalState.getEmittedCircuit.value)).serialize
val expected = parse(check).serialize
logger.debug(actual)
logger.debug(expected)
(actual) should be (expected)
}
// Executes the test, should throw an error
- def failingexecute(writer: Writer, annotations: AnnotationMap, input: String): Exception = {
+ def failingexecute(annotations: AnnotationMap, input: String): Exception = {
intercept[PassExceptions] {
- compile(CircuitState(parse(input), ChirrtlForm, Some(annotations)), writer)
+ compile(CircuitState(parse(input), ChirrtlForm, Some(annotations)), Seq.empty)
}
}
}
@@ -65,6 +43,7 @@ class CustomResolveAndCheck(form: CircuitForm) extends PassBasedTransform {
}
trait LowTransformSpec extends SimpleTransformSpec {
+ def emitter = new LowFirrtlEmitter
def transform: Transform
def transforms = Seq(
new ChirrtlToHighFirrtl(),
@@ -78,6 +57,7 @@ trait LowTransformSpec extends SimpleTransformSpec {
}
trait MiddleTransformSpec extends SimpleTransformSpec {
+ def emitter = new MiddleFirrtlEmitter
def transform: Transform
def transforms = Seq(
new ChirrtlToHighFirrtl(),
@@ -90,6 +70,7 @@ trait MiddleTransformSpec extends SimpleTransformSpec {
}
trait HighTransformSpec extends SimpleTransformSpec {
+ def emitter = new HighFirrtlEmitter
def transform: Transform
def transforms = Seq(
new ChirrtlToHighFirrtl(),
diff --git a/src/test/scala/firrtlTests/ReplSeqMemTests.scala b/src/test/scala/firrtlTests/ReplSeqMemTests.scala
index 01a4501b..1a5b44e6 100644
--- a/src/test/scala/firrtlTests/ReplSeqMemTests.scala
+++ b/src/test/scala/firrtlTests/ReplSeqMemTests.scala
@@ -9,6 +9,7 @@ import firrtl.passes.memlib._
import annotations._
class ReplSeqMemSpec extends SimpleTransformSpec {
+ def emitter = new LowFirrtlEmitter
def transforms = Seq(
new ChirrtlToHighFirrtl(),
new IRToWorkingIR(),
@@ -62,10 +63,9 @@ circuit Top :
""".stripMargin
val confLoc = "ReplSeqMemTests.confTEMP"
val aMap = AnnotationMap(Seq(ReplSeqMemAnnotation("-c:Top:-o:"+confLoc)))
- val writer = new java.io.StringWriter
- compile(CircuitState(parse(input), ChirrtlForm, Some(aMap)), writer)
+ val res = compileAndEmit(CircuitState(parse(input), ChirrtlForm, Some(aMap)))
// Check correctness of firrtl
- parse(writer.toString)
+ parse(res.getEmittedCircuit.value)
(new java.io.File(confLoc)).delete()
}
@@ -85,10 +85,9 @@ circuit Top :
""".stripMargin
val confLoc = "ReplSeqMemTests.confTEMP"
val aMap = AnnotationMap(Seq(ReplSeqMemAnnotation("-c:Top:-o:"+confLoc)))
- val writer = new java.io.StringWriter
- compile(CircuitState(parse(input), ChirrtlForm, Some(aMap)), writer)
+ val res = compileAndEmit(CircuitState(parse(input), ChirrtlForm, Some(aMap)))
// Check correctness of firrtl
- parse(writer.toString)
+ parse(res.getEmittedCircuit.value)
(new java.io.File(confLoc)).delete()
}
@@ -111,10 +110,9 @@ circuit CustomMemory :
""".stripMargin
val confLoc = "ReplSeqMemTests.confTEMP"
val aMap = AnnotationMap(Seq(ReplSeqMemAnnotation("-c:CustomMemory:-o:"+confLoc)))
- val writer = new java.io.StringWriter
- compile(CircuitState(parse(input), ChirrtlForm, Some(aMap)), writer)
+ val res = compileAndEmit(CircuitState(parse(input), ChirrtlForm, Some(aMap)))
// Check correctness of firrtl
- parse(writer.toString)
+ parse(res.getEmittedCircuit.value)
(new java.io.File(confLoc)).delete()
}
@@ -137,10 +135,9 @@ circuit CustomMemory :
""".stripMargin
val confLoc = "ReplSeqMemTests.confTEMP"
val aMap = AnnotationMap(Seq(ReplSeqMemAnnotation("-c:CustomMemory:-o:"+confLoc)))
- val writer = new java.io.StringWriter
- compile(CircuitState(parse(input), ChirrtlForm, Some(aMap)), writer)
+ val res = compileAndEmit(CircuitState(parse(input), ChirrtlForm, Some(aMap)))
// Check correctness of firrtl
- parse(writer.toString)
+ parse(res.getEmittedCircuit.value)
(new java.io.File(confLoc)).delete()
}
@@ -213,10 +210,9 @@ circuit CustomMemory :
val aMap = AnnotationMap(Seq(
ReplSeqMemAnnotation("-c:CustomMemory:-o:"+confLoc),
NoDedupMemAnnotation(ComponentName("mem_0", ModuleName("CustomMemory",CircuitName("CustomMemory"))))))
- val writer = new java.io.StringWriter
- compile(CircuitState(parse(input), ChirrtlForm, Some(aMap)), writer)
+ val res = compileAndEmit(CircuitState(parse(input), ChirrtlForm, Some(aMap)))
// Check correctness of firrtl
- val circuit = parse(writer.toString)
+ val circuit = parse(res.getEmittedCircuit.value)
val numExtMods = circuit.modules.count {
case e: ExtModule => true
case _ => false
@@ -254,10 +250,9 @@ circuit CustomMemory :
val aMap = AnnotationMap(Seq(
ReplSeqMemAnnotation("-c:CustomMemory:-o:"+confLoc),
NoDedupMemAnnotation(ComponentName("mem_1", ModuleName("CustomMemory",CircuitName("CustomMemory"))))))
- val writer = new java.io.StringWriter
- compile(CircuitState(parse(input), ChirrtlForm, Some(aMap)), writer)
+ val res = compileAndEmit(CircuitState(parse(input), ChirrtlForm, Some(aMap)))
// Check correctness of firrtl
- val circuit = parse(writer.toString)
+ val circuit = parse(res.getEmittedCircuit.value)
val numExtMods = circuit.modules.count {
case e: ExtModule => true
case _ => false
@@ -289,10 +284,9 @@ circuit CustomMemory :
"""
val confLoc = "ReplSeqMemTests.confTEMP"
val aMap = AnnotationMap(Seq(ReplSeqMemAnnotation("-c:CustomMemory:-o:"+confLoc)))
- val writer = new java.io.StringWriter
- compile(CircuitState(parse(input), ChirrtlForm, Some(aMap)), writer)
+ val res = compileAndEmit(CircuitState(parse(input), ChirrtlForm, Some(aMap)))
// Check correctness of firrtl
- val circuit = parse(writer.toString)
+ val circuit = parse(res.getEmittedCircuit.value)
val numExtMods = circuit.modules.count {
case e: ExtModule => true
case _ => false
diff --git a/src/test/scala/firrtlTests/UnitTests.scala b/src/test/scala/firrtlTests/UnitTests.scala
index ec328818..3cf25d3a 100644
--- a/src/test/scala/firrtlTests/UnitTests.scala
+++ b/src/test/scala/firrtlTests/UnitTests.scala
@@ -107,7 +107,7 @@ class UnitTests extends FirrtlFlatSpec {
(c: Circuit, p: Pass) => p.run(c)
}
val writer = new StringWriter()
- (new FirrtlEmitter).emit(CircuitState(c_result, HighForm), writer)
+ (new HighFirrtlEmitter).emit(CircuitState(c_result, HighForm), writer)
(parse(writer.toString())) should be (parse(check))
}
@@ -129,7 +129,8 @@ class UnitTests extends FirrtlFlatSpec {
intercept[PassException] {
val c = Parser.parse(splitExpTestCode.split("\n").toIterator)
val c2 = passes.foldLeft(c)((c, p) => p run c)
- (new VerilogEmitter).emit(CircuitState(c2, LowForm), new StringWriter)
+ val writer = new StringWriter()
+ (new VerilogEmitter).emit(CircuitState(c2, LowForm), writer)
}
}
@@ -140,7 +141,8 @@ class UnitTests extends FirrtlFlatSpec {
InferTypes)
val c = Parser.parse(splitExpTestCode.split("\n").toIterator)
val c2 = passes.foldLeft(c)((c, p) => p run c)
- (new VerilogEmitter).emit(CircuitState(c2, LowForm), new StringWriter)
+ val writer = new StringWriter()
+ (new VerilogEmitter).emit(CircuitState(c2, LowForm), writer)
}
"Simple compound expressions" should "be split" in {
diff --git a/src/test/scala/firrtlTests/VerilogEmitterTests.scala b/src/test/scala/firrtlTests/VerilogEmitterTests.scala
index 862a9605..6928718a 100644
--- a/src/test/scala/firrtlTests/VerilogEmitterTests.scala
+++ b/src/test/scala/firrtlTests/VerilogEmitterTests.scala
@@ -12,14 +12,6 @@ import firrtl.passes._
import firrtl.Parser.IgnoreInfo
class DoPrimVerilog extends FirrtlFlatSpec {
- private def executeTest(input: String, expected: Seq[String], compiler: Compiler) = {
- val writer = new StringWriter()
- compiler.compile(CircuitState(parse(input), ChirrtlForm), writer)
- val lines = writer.toString().split("\n") map normalized
- expected foreach { e =>
- lines should contain(e)
- }
- }
"Xorr" should "emit correctly" in {
val compiler = new VerilogCompiler
val input =
diff --git a/src/test/scala/firrtlTests/fixed/FixedPointMathSpec.scala b/src/test/scala/firrtlTests/fixed/FixedPointMathSpec.scala
index 0c30b59e..39da2a33 100644
--- a/src/test/scala/firrtlTests/fixed/FixedPointMathSpec.scala
+++ b/src/test/scala/firrtlTests/fixed/FixedPointMathSpec.scala
@@ -2,8 +2,6 @@
package firrtlTests.fixed
-import java.io.StringWriter
-
import firrtl.{CircuitState, ChirrtlForm, LowFirrtlCompiler, Parser, AnnotationMap}
import firrtl.Parser.IgnoreInfo
import firrtlTests.FirrtlFlatSpec
@@ -41,11 +39,9 @@ class FixedPointMathSpec extends FirrtlFlatSpec {
val lowerer = new LowFirrtlCompiler
- val writer = new StringWriter()
-
- lowerer.compile(CircuitState(parse(input), ChirrtlForm), writer)
+ val res = lowerer.compileAndEmit(CircuitState(parse(input), ChirrtlForm))
- val output = writer.toString.split("\n")
+ val output = res.getEmittedCircuit.value split "\n"
def inferredAddWidth: Int = {
val binaryDifference = binaryPoint1 - binaryPoint2
diff --git a/src/test/scala/firrtlTests/fixed/FixedTypeInferenceSpec.scala b/src/test/scala/firrtlTests/fixed/FixedTypeInferenceSpec.scala
index 44fa1d29..37209786 100644
--- a/src/test/scala/firrtlTests/fixed/FixedTypeInferenceSpec.scala
+++ b/src/test/scala/firrtlTests/fixed/FixedTypeInferenceSpec.scala
@@ -20,14 +20,6 @@ class FixedTypeInferenceSpec extends FirrtlFlatSpec {
lines should contain(e)
}
}
- private def executeTest(input: String, expected: Seq[String], compiler: Compiler) = {
- val writer = new StringWriter()
- compiler.compile(CircuitState(parse(input), ChirrtlForm), writer)
- val lines = writer.toString().split("\n") map normalized
- expected foreach { e =>
- lines should contain(e)
- }
- }
"Fixed types" should "infer add correctly" in {
val passes = Seq(
diff --git a/src/test/scala/firrtlTests/transforms/BlacklBoxSourceHelperSpec.scala b/src/test/scala/firrtlTests/transforms/BlacklBoxSourceHelperSpec.scala
index b037accf..8cd51b2a 100644
--- a/src/test/scala/firrtlTests/transforms/BlacklBoxSourceHelperSpec.scala
+++ b/src/test/scala/firrtlTests/transforms/BlacklBoxSourceHelperSpec.scala
@@ -2,8 +2,6 @@
package firrtlTests.transforms
-import java.io.StringWriter
-
import firrtl.annotations.{Annotation, CircuitName, ModuleName}
import firrtl.transforms._
import firrtl.{AnnotationMap, FIRRTLException, Transform, VerilogCompiler}
@@ -80,13 +78,12 @@ class BlacklBoxSourceHelperTransformSpec extends LowTransformSpec {
"annotated external modules" should "appear in output directory" in {
- val writer = new StringWriter()
val aMap = AnnotationMap(Seq(
Annotation(moduleName, classOf[BlackBoxSourceHelper], BlackBoxTargetDir("test_run_dir").serialize),
Annotation(moduleName, classOf[BlackBoxSourceHelper], BlackBoxResource("/blackboxes/AdderExtModule.v").serialize)
))
- execute(writer, aMap, input, output)
+ execute(aMap, input, output)
new java.io.File("test_run_dir/AdderExtModule.v").exists should be (true)
new java.io.File(s"test_run_dir/${BlackBoxSourceHelper.FileListName}").exists should be (true)
diff --git a/src/test/scala/firrtlTests/transforms/DedupTests.scala b/src/test/scala/firrtlTests/transforms/DedupTests.scala
index 62015388..7148dd11 100644
--- a/src/test/scala/firrtlTests/transforms/DedupTests.scala
+++ b/src/test/scala/firrtlTests/transforms/DedupTests.scala
@@ -3,8 +3,6 @@
package firrtlTests
package transform
-import java.io.StringWriter
-
import org.scalatest.FlatSpec
import org.scalatest.Matchers
import org.scalatest.junit.JUnitRunner
@@ -48,9 +46,8 @@ class DedupModuleTests extends HighTransformSpec {
| output x: UInt<1>
| x <= UInt(1)
""".stripMargin
- val writer = new StringWriter()
val aMap = new AnnotationMap(Nil)
- execute(writer, aMap, input, check)
+ execute(aMap, input, check)
}
"The module A and B" should "be deduped" in {
val input =
@@ -86,9 +83,8 @@ class DedupModuleTests extends HighTransformSpec {
| output x: UInt<1>
| x <= UInt(1)
""".stripMargin
- val writer = new StringWriter()
val aMap = new AnnotationMap(Nil)
- execute(writer, aMap, input, check)
+ execute(aMap, input, check)
}
"The module A and B with comments" should "be deduped" in {
val input =
@@ -124,9 +120,8 @@ class DedupModuleTests extends HighTransformSpec {
| output x: UInt<1>
| x <= UInt(1)
""".stripMargin
- val writer = new StringWriter()
val aMap = new AnnotationMap(Nil)
- execute(writer, aMap, input, check)
+ execute(aMap, input, check)
}
"The module B, but not A, with comments" should "be deduped if not annotated" in {
val input =
@@ -153,9 +148,8 @@ class DedupModuleTests extends HighTransformSpec {
| output x: UInt<1> @[xx 1:1]
| x <= UInt(1)
""".stripMargin
- val writer = new StringWriter()
val aMap = new AnnotationMap(Seq(NoDedupAnnotation(ModuleName("A", CircuitName("Top")))))
- execute(writer, aMap, input, check)
+ execute(aMap, input, check)
}
}