diff --git a/tapeout/src/main/scala/transforms/Generate.scala b/tapeout/src/main/scala/transforms/Generate.scala index 2c68a4e8..f9b3e8dc 100644 --- a/tapeout/src/main/scala/transforms/Generate.scala +++ b/tapeout/src/main/scala/transforms/Generate.scala @@ -15,10 +15,10 @@ object AllModules { def add(module: String) = { modules = modules | Set(module) } - def rename(module: String) = { + def rename(module: String, suffix: String = "_inTestHarness") = { var new_name = module while (modules.contains(new_name)) - new_name = new_name + "_inTestHarness" + new_name = new_name + suffix new_name } } @@ -28,17 +28,6 @@ trait HasTapeoutOptions { self: ExecutionOptionsManager with HasFirrtlOptions => parser.note("tapeout options") - parser.opt[String]("top-o") - .abbr("tto") - .valueName("") - .foreach { x => - tapeoutOptions = tapeoutOptions.copy( - topOutput = Some(x) - ) - }.text { - "use this to generate top at " - } - parser.opt[String]("harness-o") .abbr("tho") .valueName("") @@ -72,173 +61,87 @@ trait HasTapeoutOptions { self: ExecutionOptionsManager with HasFirrtlOptions => "use this to set harnessTop" } - parser.opt[String]("list-clocks") - .abbr("tlc") - .valueName("") - .foreach { x => - tapeoutOptions = tapeoutOptions.copy( - listClocks = Some(x) - ) - }.text { - "use this to list " - } - parser.note("") } case class TapeoutOptions( - input: Option[String] = None, - output: Option[String] = None, - topOutput: Option[String] = None, harnessOutput: Option[String] = None, - annoFile: Option[String] = None, synTop: Option[String] = None, - harnessTop: Option[String] = None, - seqMemFlags: Option[String] = Some("-o:unused.confg"), - listClocks: Option[String] = Some("-o:unused.clocks") + harnessTop: Option[String] = None ) extends LazyLogging // Requires two phases, one to collect modules below synTop in the hierarchy // and a second to remove those modules to generate the test harness sealed trait GenerateTopAndHarnessApp extends LazyLogging { this: App => - lazy val optionsManager = { + def getOptionsManager = { val optionsManager = new ExecutionOptionsManager("tapeout") with HasFirrtlOptions with HasTapeoutOptions if (!optionsManager.parse(args)) { throw new Exception("Error parsing options!") } optionsManager } - lazy val options = optionsManager.tapeoutOptions - lazy val input = options.input - lazy val output = options.output - lazy val topOutput = options.topOutput - lazy val harnessOutput = options.harnessOutput - lazy val annoFile = options.annoFile - lazy val synTop = options.synTop - lazy val harnessTop = options.harnessTop - lazy val seqMemFlags = options.seqMemFlags - lazy val listClocks = options.listClocks + lazy val optionsManager = getOptionsManager + lazy val tapeoutOptions = optionsManager.tapeoutOptions + // Tapeout options + lazy val harnessOutput = tapeoutOptions.harnessOutput + lazy val synTop = tapeoutOptions.synTop + lazy val harnessTop = tapeoutOptions.harnessTop - private def getFirstPhasePasses(top: Boolean, harness: Boolean): Seq[Transform] = { - val pre = Seq( + lazy val firrtlOptions = optionsManager.firrtlOptions + // FIRRTL options + lazy val annoFiles = firrtlOptions.annotationFileNames + + private def getFirstPhasePasses: Seq[Transform] = { + Seq( new ReParentCircuit(synTop.get), + new RemoveUnusedModules ) - - val enumerate = if (harness) { Seq( - new EnumerateModules( { m => if (m.name != options.harnessTop.get && m.name != options.synTop.get) { AllModules.add(m.name) } } ), - ) } else Seq() - - val post = if (top) { Seq( - new RemoveUnusedModules, - new passes.memlib.InferReadWrite(), - new passes.clocklist.ClockListTransform() - ) } else Seq() - - pre ++ enumerate ++ post - } - - private def getFirstPhaseAnnotations(top: Boolean): AnnotationSeq = { - if (top) { - //Load annotations from file - val annotationArray: Seq[Annotation] = annoFile match { - case None => Array[Annotation]() - case Some(fileName) => { - val annotations = new File(fileName) - if(annotations.exists) { - val annotationsYaml = io.Source.fromFile(annotations).getLines().mkString("\n") - Seq(AnnotationUtils.fromYaml(annotationsYaml)) // TODO - } else { - Seq[Annotation]() - } - } - } - // add new annotations - AnnotationSeq(Seq( - passes.memlib.InferReadWriteAnnotation, - passes.clocklist.ClockListAnnotation.parse( - s"-c:${synTop.get}:-m:${synTop.get}:${listClocks.get}" - ), - passes.memlib.ReplSeqMemAnnotation.parse( - s"-c:${synTop.get}:${seqMemFlags.get}" - ) - ) ++ annotationArray) - } else { AnnotationSeq(Seq.empty) } } private def getSecondPhasePasses: Seq[Transform] = { - // always the same for now Seq( new ConvertToExtMod((m) => m.name == synTop.get), - new RenameModulesAndInstances((m) => AllModules.rename(m)), - // new RemoveUnusedModules, + new EnumerateModules( { m => if (m.name != tapeoutOptions.harnessTop.get && m.name != tapeoutOptions.synTop.get) { AllModules.add(m.name) } } ), + new RenameModulesAndInstances((m) => AllModules.rename(m, "_in" + harnessTop.get)), + new RemoveUnusedModules ) } - // always the same for now - private def getSecondPhaseAnnotations: AnnotationSeq = AnnotationSeq(Seq.empty) - // Top Generation - protected def firstPhase(top: Boolean, harness: Boolean): Unit = { - require(top || harness, "Must specify either top or harness") + protected def firstPhase: Unit = { - val firrtlOptions = optionsManager.firrtlOptions - optionsManager.firrtlOptions = firrtlOptions.copy( - annotations = firrtlOptions.annotations ++ getFirstPhaseAnnotations(top) + val firstPhaseOptions = getOptionsManager + firstPhaseOptions.firrtlOptions = firstPhaseOptions.firrtlOptions.copy( + customTransforms = firrtlOptions.customTransforms ++ getFirstPhasePasses ) - optionsManager.firrtlOptions = firrtlOptions.copy( - customTransforms = firrtlOptions.customTransforms ++ getFirstPhasePasses(top, harness) - ) + firrtl.Driver.execute(firstPhaseOptions) } // Harness Generation protected def secondPhase: Unit = { - val firrtlOptions = optionsManager.firrtlOptions - optionsManager.firrtlOptions = firrtlOptions.copy( - annotations = firrtlOptions.annotations ++ getSecondPhaseAnnotations + val secondPhaseOptions = getOptionsManager + secondPhaseOptions.firrtlOptions = secondPhaseOptions.firrtlOptions.copy( + outputFileNameOverride = harnessOutput.get, + customTransforms = getSecondPhasePasses ) - optionsManager.firrtlOptions = firrtlOptions.copy( - customTransforms = firrtlOptions.customTransforms ++ getSecondPhasePasses - ) - } - - protected def execute: Unit = { - firrtl.Driver.execute(optionsManager) + firrtl.Driver.execute(secondPhaseOptions) } } object GenerateTop extends App with GenerateTopAndHarnessApp { - // warn about unused options - harnessOutput.foreach(n => logger.warn(s"Not using harness output filename $n since you asked for just a top-level output.")) - topOutput.foreach( - n => logger.warn(s"Not using generic output filename $n since you asked for just a top-level output and also specified a generic output.")) // Only need a single phase to generate the top module - firstPhase(top = true, harness = false) - execute + firstPhase } object GenerateHarness extends App with GenerateTopAndHarnessApp { - // warn about unused options - topOutput.foreach(n => logger.warn(s"Not using top-level output filename $n since you asked for just a test harness.")) - annoFile.foreach(n => logger.warn(s"Not using annotations file $n since you asked for just a test harness.")) - seqMemFlags.filter(_ != "-o:unused.confg").foreach { - n => logger.warn(s"Not using SeqMem flags $n since you asked for just a test harness.") } - listClocks.filter(_ != "-o:unused.clocks").foreach { - n => logger.warn(s"Not using clocks list $n since you asked for just a test harness.") } - harnessOutput.foreach( - n => logger.warn(s"Not using generic output filename $n since you asked for just a test harness and also specified a generic output.")) // Do minimal work for the first phase to generate test harness - firstPhase(top = false, harness = true) secondPhase - execute } object GenerateTopAndHarness extends App with GenerateTopAndHarnessApp { - // warn about unused options - output.foreach(n => logger.warn(s"Not using generic output filename $n since you asked for both a top-level output and a test harness.")) // Do everything, top and harness generation - firstPhase(top = true, harness = true) + firstPhase secondPhase - execute }