From 79b8fd324be70f6fd96ced62b733f67dd0aac1da Mon Sep 17 00:00:00 2001 From: John Wright Date: Fri, 8 Feb 2019 01:40:59 -0800 Subject: [PATCH] This compiles and works correctly, but is kind of hacky, and will break as soon as any additional external/blackbox modules are added to the test harness. The test harness should detect external modules and not rename them instead of what is happening here. --- mdf | 2 +- .../src/main/scala/transforms/Generate.scala | 61 ++++++------------- .../transforms/RemoveUnusedModules.scala | 42 +++++++------ 3 files changed, 43 insertions(+), 62 deletions(-) diff --git a/mdf b/mdf index ee50cc2b..c13e3165 160000 --- a/mdf +++ b/mdf @@ -1 +1 @@ -Subproject commit ee50cc2b096c5d7f64afdd9a54db40a9cc2ca484 +Subproject commit c13e31656e1ce572e03acf465beb00e157dcbc06 diff --git a/tapeout/src/main/scala/transforms/Generate.scala b/tapeout/src/main/scala/transforms/Generate.scala index f9b3e8dc..8d4caccc 100644 --- a/tapeout/src/main/scala/transforms/Generate.scala +++ b/tapeout/src/main/scala/transforms/Generate.scala @@ -10,19 +10,6 @@ import firrtl.annotations.AnnotationYamlProtocol._ import net.jcazevedo.moultingyaml._ import com.typesafe.scalalogging.LazyLogging -object AllModules { - private var modules = Set[String]() - def add(module: String) = { - modules = modules | Set(module) - } - def rename(module: String, suffix: String = "_inTestHarness") = { - var new_name = module - while (modules.contains(new_name)) - new_name = new_name + suffix - new_name - } -} - trait HasTapeoutOptions { self: ExecutionOptionsManager with HasFirrtlOptions => var tapeoutOptions = TapeoutOptions() @@ -61,7 +48,6 @@ trait HasTapeoutOptions { self: ExecutionOptionsManager with HasFirrtlOptions => "use this to set harnessTop" } - parser.note("") } case class TapeoutOptions( @@ -73,75 +59,66 @@ case class TapeoutOptions( // 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 => - def getOptionsManager = { + lazy val optionsManager = { val optionsManager = new ExecutionOptionsManager("tapeout") with HasFirrtlOptions with HasTapeoutOptions if (!optionsManager.parse(args)) { throw new Exception("Error parsing options!") } optionsManager } - 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 - lazy val firrtlOptions = optionsManager.firrtlOptions // FIRRTL options lazy val annoFiles = firrtlOptions.annotationFileNames - private def getFirstPhasePasses: Seq[Transform] = { + private def topTransforms: Seq[Transform] = { Seq( new ReParentCircuit(synTop.get), new RemoveUnusedModules ) } - private def getSecondPhasePasses: Seq[Transform] = { + + private def harnessTransforms: Seq[Transform] = { + // XXX this is a hack, we really should be checking the masters to see if they are ExtModules + val externals = Set(harnessTop.get, synTop.get, "SimSerial") Seq( new ConvertToExtMod((m) => m.name == synTop.get), - 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 + new RemoveUnusedModules, + new RenameModulesAndInstances((old) => if (externals contains old) old else (old + "_in" + harnessTop.get)) ) } // Top Generation - protected def firstPhase: Unit = { + protected def executeTop: Unit = { - val firstPhaseOptions = getOptionsManager - firstPhaseOptions.firrtlOptions = firstPhaseOptions.firrtlOptions.copy( - customTransforms = firrtlOptions.customTransforms ++ getFirstPhasePasses + optionsManager.firrtlOptions = optionsManager.firrtlOptions.copy( + customTransforms = firrtlOptions.customTransforms ++ topTransforms ) - firrtl.Driver.execute(firstPhaseOptions) + firrtl.Driver.execute(optionsManager) } // Harness Generation - protected def secondPhase: Unit = { - val secondPhaseOptions = getOptionsManager - secondPhaseOptions.firrtlOptions = secondPhaseOptions.firrtlOptions.copy( - outputFileNameOverride = harnessOutput.get, - customTransforms = getSecondPhasePasses + protected def executeHarness: Unit = { + + optionsManager.firrtlOptions = optionsManager.firrtlOptions.copy( + customTransforms = harnessTransforms ) - firrtl.Driver.execute(secondPhaseOptions) + firrtl.Driver.execute(optionsManager) } } object GenerateTop extends App with GenerateTopAndHarnessApp { // Only need a single phase to generate the top module - firstPhase + executeTop } object GenerateHarness extends App with GenerateTopAndHarnessApp { // Do minimal work for the first phase to generate test harness - secondPhase -} - -object GenerateTopAndHarness extends App with GenerateTopAndHarnessApp { - // Do everything, top and harness generation - firstPhase - secondPhase + executeHarness } diff --git a/tapeout/src/main/scala/transforms/RemoveUnusedModules.scala b/tapeout/src/main/scala/transforms/RemoveUnusedModules.scala index 848b7a2c..410c7326 100644 --- a/tapeout/src/main/scala/transforms/RemoveUnusedModules.scala +++ b/tapeout/src/main/scala/transforms/RemoveUnusedModules.scala @@ -5,13 +5,15 @@ package barstools.tapeout.transforms import firrtl._ import firrtl.ir._ import firrtl.passes.Pass +import firrtl.annotations.{SingleTargetAnnotation, Annotation} +import firrtl.transforms.DontTouchAnnotation -// Removes all the unused modules in a circuit by recursing through every -// instance (starting at the main module) -class RemoveUnusedModulesPass extends Pass { +class RemoveUnusedModules extends Transform { + def inputForm = MidForm + def outputForm = MidForm - def run(c: Circuit): Circuit = { - val modulesByName = c.modules.map{ + def execute(state: CircuitState): CircuitState = { + val modulesByName = state.circuit.modules.map{ case m: Module => (m.name, Some(m)) case m: ExtModule => (m.name, None) }.toMap @@ -39,21 +41,23 @@ class RemoveUnusedModulesPass extends Pass { case None => Set.empty[String] } } - val usedModuleSet = getUsedModules(modulesByName(c.main)) + val usedModuleSet = getUsedModules(modulesByName(state.circuit.main)) - val usedModuleSeq = c.modules.filter { usedModuleSet contains _.name } + val usedModuleSeq = state.circuit.modules.filter { usedModuleSet contains _.name } + val usedModuleNames = usedModuleSeq.map(_.name) - Circuit(c.info, usedModuleSeq, c.main) - } -} - -class RemoveUnusedModules extends Transform with SeqTransformBased { - def inputForm = MidForm - def outputForm = MidForm - def transforms = Seq(new RemoveUnusedModulesPass) - - def execute(state: CircuitState): CircuitState = { - val ret = runTransforms(state) - CircuitState(ret.circuit, outputForm, ret.annotations, ret.renames) + val renames = state.renames.getOrElse(RenameMap()) + + //state.circuit.modules.filterNot { usedModuleSet contains _.name } foreach { x => renames.record(ModuleTarget(state.circuit.main, x.name), Seq()) } + + val newCircuit = Circuit(state.circuit.info, usedModuleSeq, state.circuit.main) + val newAnnos = AnnotationSeq(state.annotations.toSeq.filter { _ match { + // XXX This is wrong, but it works for now + case x: DontTouchAnnotation => false + //case x: DontTouchAnnotation => usedModuleNames contains x.target.module + case _ => true + }}) + + CircuitState(newCircuit, outputForm, newAnnos, Some(renames)) } }