diff --git a/src/main/scala/barstools/tapeout/transforms/AddSuffixToModuleNames.scala b/src/main/scala/barstools/tapeout/transforms/AddSuffixToModuleNames.scala deleted file mode 100644 index e2c5620d..00000000 --- a/src/main/scala/barstools/tapeout/transforms/AddSuffixToModuleNames.scala +++ /dev/null @@ -1,71 +0,0 @@ -// See LICENSE for license details. - -package barstools.tapeout.transforms - -import firrtl.Mappers._ -import firrtl._ -import firrtl.annotations.{CircuitTarget, ModuleTarget, SingleTargetAnnotation} -import firrtl.ir._ -import firrtl.stage.Forms -import firrtl.stage.TransformManager.TransformDependency - -case class KeepNameAnnotation(target: ModuleTarget) extends SingleTargetAnnotation[ModuleTarget] { - def duplicate(n: ModuleTarget) = this.copy(n) -} - -case class ModuleNameSuffixAnnotation(target: CircuitTarget, suffix: String) - extends SingleTargetAnnotation[CircuitTarget] { - def duplicate(n: CircuitTarget) = this.copy(target = n) -} - -class AddSuffixToModuleNames extends Transform with DependencyAPIMigration { - - override def prerequisites: Seq[TransformDependency] = Forms.LowForm - override def optionalPrerequisites: Seq[TransformDependency] = Forms.LowFormOptimized - override def optionalPrerequisiteOf: Seq[TransformDependency] = Forms.LowEmitters - override def invalidates(a: Transform): Boolean = false - - def determineRenamerandAnnos(state: CircuitState): (AnnotationSeq, (String) => String) = { - // remove determine suffix annotation - val newAnnos = state.annotations.filterNot(_.isInstanceOf[ModuleNameSuffixAnnotation]) - val suffixes = state.annotations.collect({ case ModuleNameSuffixAnnotation(_, suffix) => suffix }) - require(suffixes.length <= 1) - val suffix = suffixes.headOption.getOrElse("") - - // skip renaming ExtModules and top-level module - val excludeSet = state.circuit.modules.flatMap { - case e: ExtModule => Some(e.name) - case m if (m.name == state.circuit.main) => Some(m.name) - case _ => None - }.toSet - - val renamer = { (name: String) => if (excludeSet(name)) name else name + suffix } - - (newAnnos, renamer) - } - - def renameInstanceModules(renamer: (String) => String)(stmt: Statement): Statement = { - stmt match { - case m: DefInstance => new DefInstance(m.info, m.name, renamer(m.module)) - case s => s.map(renameInstanceModules(renamer)) // if is statement, recurse - } - } - - def run(state: CircuitState, renamer: (String) => String): (Circuit, RenameMap) = { - val myRenames = RenameMap() - val c = state.circuit - val modulesx = c.modules.map { - case m if (renamer(m.name) != m.name) => - myRenames.record(ModuleTarget(c.main, m.name), ModuleTarget(c.main, renamer(m.name))) - m.map(renamer).map(renameInstanceModules(renamer)) - case m => m.map(renameInstanceModules(renamer)) - } - (Circuit(c.info, modulesx, c.main), myRenames) - } - - def execute(state: CircuitState): CircuitState = { - val (newAnnos, renamer) = determineRenamerandAnnos(state) - val (ret, renames) = run(state, renamer) - state.copy(circuit = ret, annotations = newAnnos, renames = Some(renames)) - } -} diff --git a/src/main/scala/barstools/tapeout/transforms/AvoidExtModuleCollisions.scala b/src/main/scala/barstools/tapeout/transforms/AvoidExtModuleCollisions.scala deleted file mode 100644 index 127a37fa..00000000 --- a/src/main/scala/barstools/tapeout/transforms/AvoidExtModuleCollisions.scala +++ /dev/null @@ -1,32 +0,0 @@ -// See LICENSE for license details. - -package barstools.tapeout.transforms - -import firrtl._ -import firrtl.annotations.NoTargetAnnotation -import firrtl.ir._ -import firrtl.options.Dependency -import firrtl.passes.memlib.ReplSeqMem -import firrtl.stage.Forms -import firrtl.stage.TransformManager.TransformDependency - -case class LinkExtModulesAnnotation(mustLink: Seq[ExtModule]) extends NoTargetAnnotation - -class AvoidExtModuleCollisions extends Transform with DependencyAPIMigration { - - override def prerequisites: Seq[TransformDependency] = Forms.HighForm - override def optionalPrerequisites: Seq[TransformDependency] = Seq(Dependency[RemoveUnusedModules]) - override def optionalPrerequisiteOf: Seq[TransformDependency] = { - Forms.HighEmitters :+ Dependency[ReplSeqMem] - } - override def invalidates(a: Transform): Boolean = false - - def execute(state: CircuitState): CircuitState = { - val mustLink = state.annotations.flatMap { - case LinkExtModulesAnnotation(mustLink) => mustLink - case _ => Nil - } - val newAnnos = state.annotations.filterNot(_.isInstanceOf[LinkExtModulesAnnotation]) - state.copy(circuit = state.circuit.copy(modules = state.circuit.modules ++ mustLink), annotations = newAnnos) - } -} diff --git a/src/main/scala/barstools/tapeout/transforms/ConvertToExtModPass.scala b/src/main/scala/barstools/tapeout/transforms/ConvertToExtModPass.scala deleted file mode 100644 index a81937a3..00000000 --- a/src/main/scala/barstools/tapeout/transforms/ConvertToExtModPass.scala +++ /dev/null @@ -1,62 +0,0 @@ -// See LICENSE for license details. - -package barstools.tapeout.transforms - -import firrtl._ -import firrtl.annotations.{ModuleTarget, ReferenceTarget, SingleTargetAnnotation} -import firrtl.ir._ -import firrtl.options.Dependency -import firrtl.passes.memlib.ReplSeqMem -import firrtl.stage.Forms -import firrtl.stage.TransformManager.TransformDependency - -case class ConvertToExtModAnnotation(target: ModuleTarget) extends SingleTargetAnnotation[ModuleTarget] { - def duplicate(n: ModuleTarget) = this.copy(n) -} - -// Converts some modules to external modules, based on a given function. If -// that function returns "true" then the module is converted into an ExtModule, -// otherwise it's left alone. -class ConvertToExtMod extends Transform with DependencyAPIMigration { - - override def prerequisites: Seq[TransformDependency] = Forms.HighForm - override def optionalPrerequisites: Seq[TransformDependency] = Seq.empty - override def optionalPrerequisiteOf: Seq[TransformDependency] = { - Forms.HighEmitters ++ Seq(Dependency[RemoveUnusedModules], Dependency[ReplSeqMem]) - } - override def invalidates(a: Transform): Boolean = false - - def run(state: CircuitState, makeExt: Set[String]): (Circuit, RenameMap) = { - val renames = RenameMap() - val c = state.circuit - renames.setCircuit(c.main) - val modulesx = c.modules.map { - case m: ExtModule => m - case m: Module => - val removing = collection.mutable.HashSet[String]() - def findDeadNames(statement: Statement): Unit = { - statement match { - case hn: IsDeclaration => removing += hn.name - case x => x.foreachStmt(findDeadNames) - } - } - if (makeExt(m.name)) { - m.foreachStmt(findDeadNames) - removing.foreach { name => - renames.record(ReferenceTarget(c.main, m.name, Nil, name, Nil), Nil) - } - new ExtModule(m.info, m.name, m.ports, m.name, Seq.empty) - } else { - m - } - } - (Circuit(c.info, modulesx, c.main), renames) - } - - def execute(state: CircuitState): CircuitState = { - val makeExt = state.annotations.collect({ case ConvertToExtModAnnotation(tgt) => tgt.module }).toSet - val newAnnos = state.annotations.filterNot(_.isInstanceOf[ConvertToExtModAnnotation]) - val (ret, renames) = run(state, makeExt) - state.copy(circuit = ret, annotations = newAnnos, renames = Some(renames)) - } -} diff --git a/src/main/scala/barstools/tapeout/transforms/EnumerateModules.scala b/src/main/scala/barstools/tapeout/transforms/EnumerateModules.scala deleted file mode 100644 index 47dae82c..00000000 --- a/src/main/scala/barstools/tapeout/transforms/EnumerateModules.scala +++ /dev/null @@ -1,40 +0,0 @@ -// See LICENSE for license details. - -package barstools.tapeout.transforms - -import firrtl._ -import firrtl.ir._ -import firrtl.passes.Pass -import firrtl.stage.Forms -import firrtl.stage.TransformManager.TransformDependency - -class EnumerateModulesPass(enumerate: (Module) => Unit) extends Pass { - - def run(c: Circuit): Circuit = { - val modulesx = c.modules.map { - case m: ExtModule => m - case m: Module => { - enumerate(m) - m - } - } - Circuit(c.info, modulesx, c.main) - } -} - -class EnumerateModules(enumerate: (Module) => Unit) - extends Transform - with SeqTransformBased - with DependencyAPIMigration { - - override def prerequisites: Seq[TransformDependency] = Forms.LowForm - override def optionalPrerequisites: Seq[TransformDependency] = Forms.LowFormOptimized - override def optionalPrerequisiteOf: Seq[TransformDependency] = Forms.LowEmitters - override def invalidates(a: Transform): Boolean = false - - def transforms: Seq[Transform] = Seq(new EnumerateModulesPass(enumerate)) - - def execute(state: CircuitState): CircuitState = { - runTransforms(state) - } -} diff --git a/src/main/scala/barstools/tapeout/transforms/ExtraTransforms.scala b/src/main/scala/barstools/tapeout/transforms/ExtraTransforms.scala new file mode 100644 index 00000000..8cb07551 --- /dev/null +++ b/src/main/scala/barstools/tapeout/transforms/ExtraTransforms.scala @@ -0,0 +1,26 @@ +// See LICENSE for license details. + +package barstools.tapeout.transforms + +import firrtl.Mappers._ +import firrtl._ +import firrtl.annotations.{CircuitTarget, ModuleTarget, SingleTargetAnnotation} +import firrtl.ir._ +import firrtl.stage.Forms +import firrtl.stage.TransformManager.TransformDependency +import firrtl.options.{Dependency} + +class ExtraLowTransforms extends Transform with DependencyAPIMigration { + // this PropagatePresetAnnotations is needed to run the RemoveValidIf pass (that is removed from CIRCT). + // additionally, since that pass isn't explicitly a prereq of the LowFormEmitter it + // needs to wrapped in this xform + override def prerequisites: Seq[TransformDependency] = Forms.LowForm :+ + Dependency[firrtl.transforms.PropagatePresetAnnotations] + override def optionalPrerequisites: Seq[TransformDependency] = Forms.LowFormOptimized + override def optionalPrerequisiteOf: Seq[TransformDependency] = Forms.LowEmitters + override def invalidates(a: Transform): Boolean = false + + def execute(state: CircuitState): CircuitState = { + state + } +} diff --git a/src/main/scala/barstools/tapeout/transforms/GenerateModelStageMain.scala b/src/main/scala/barstools/tapeout/transforms/GenerateModelStageMain.scala index c48d4c35..706e8606 100644 --- a/src/main/scala/barstools/tapeout/transforms/GenerateModelStageMain.scala +++ b/src/main/scala/barstools/tapeout/transforms/GenerateModelStageMain.scala @@ -5,9 +5,7 @@ import firrtl._ import firrtl.annotations._ import firrtl.ir._ import firrtl.options.{Dependency, InputAnnotationFileAnnotation, StageMain} -import firrtl.passes.memlib.ReplSeqMemAnnotation -import firrtl.stage.{FirrtlCircuitAnnotation, FirrtlStage, OutputFileAnnotation, RunFirrtlTransformAnnotation} -import firrtl.transforms.BlackBoxResourceFileNameAnno +import firrtl.stage.{FirrtlCircuitAnnotation, FirrtlStage, RunFirrtlTransformAnnotation} import logger.LazyLogging private class GenerateModelStageMain(annotations: AnnotationSeq) extends LazyLogging { @@ -38,15 +36,23 @@ private class GenerateModelStageMain(annotations: AnnotationSeq) extends LazyLog } def executeStageMain(): Unit = { - val annos = new FirrtlStage().execute(Array.empty, annotations) + val appendedAnnotations = annotations.filter(_ match { + case CompilerNameAnnotation(_) => true + case _ => false + }).map(_ match { + case CompilerNameAnnotation("low") => Some(RunFirrtlTransformAnnotation(Dependency[ExtraLowTransforms])) + case _ => None + }).flatten + val annos = new FirrtlStage().execute(Array.empty, annotations ++ appendedAnnotations) annos.collectFirst { case FirrtlCircuitAnnotation(circuit) => circuit } match { case Some(circuit) => dumpAnnos(annos) case _ => - throw new Exception(s"executeTop failed while executing FIRRTL!\n") + throw new Exception(s"executeStageMain failed while executing FIRRTL!\n") } } } +// main run class object GenerateModelStageMain extends StageMain(new TapeoutStage()) diff --git a/src/main/scala/barstools/tapeout/transforms/ReParentCircuit.scala b/src/main/scala/barstools/tapeout/transforms/ReParentCircuit.scala deleted file mode 100644 index b027a782..00000000 --- a/src/main/scala/barstools/tapeout/transforms/ReParentCircuit.scala +++ /dev/null @@ -1,76 +0,0 @@ -// See LICENSE for license details. - -package barstools.tapeout.transforms - -import firrtl._ -import firrtl.annotations._ -import firrtl.options.Dependency -import firrtl.stage.Forms -import firrtl.stage.TransformManager.TransformDependency -import firrtl.annotations.TargetToken.{Instance, OfModule} - -case class ReParentCircuitAnnotation(target: ModuleTarget) extends SingleTargetAnnotation[ModuleTarget] { - def duplicate(n: ModuleTarget) = this.copy(n) -} - -class ReParentCircuit extends Transform with DependencyAPIMigration { - - override def prerequisites: Seq[TransformDependency] = Forms.HighForm - override def optionalPrerequisites: Seq[TransformDependency] = Seq.empty - override def optionalPrerequisiteOf: Seq[TransformDependency] = { - Forms.HighEmitters :+ Dependency[RemoveUnusedModules] - } - override def invalidates(a: Transform): Boolean = false - - def execute(state: CircuitState): CircuitState = { - val c = state.circuit - val newTopName = state.annotations.collectFirst { case ReParentCircuitAnnotation(tgt) => - tgt.module - } - val newCircuit = c.copy(main = newTopName.getOrElse(c.main)) - val mainRename = newTopName.map { s => - val rmap = RenameMap() - rmap.record(CircuitTarget(c.main), CircuitTarget(s)) - rmap - } - - val newAnnotations = newTopName - .map({ topName => - // Update InstanceTargets and ReferenceTargets - // Yes, these are identical functions, but the copy methods force separate implementations - def updateInstance(t: InstanceTarget): Option[InstanceTarget] = { - val idx = t.path.lastIndexWhere(_._2.value == topName) - if (idx == -1) Some(t.copy(circuit = topName)) - else Some(t.copy(circuit = topName, module = topName, path = t.path.drop(idx + 1))) - } - def updateReference(t: ReferenceTarget): Option[ReferenceTarget] = { - val idx = t.path.lastIndexWhere(_._2.value == topName) - if (idx == -1) Some(t.copy(circuit = topName)) - else Some(t.copy(circuit = topName, module = topName, path = t.path.drop(idx + 1))) - } - - AnnotationSeq( - state.annotations.toSeq - .map({ - case x: SingleTargetAnnotation[InstanceTarget] if x.target.isInstanceOf[InstanceTarget] => - updateInstance(x.target).map(y => x.duplicate(y)) - case x: SingleTargetAnnotation[ReferenceTarget] if x.target.isInstanceOf[ReferenceTarget] => - updateReference(x.target).map(y => x.duplicate(y)) - case x: MultiTargetAnnotation => - val newTargets: Seq[Seq[Option[Target]]] = x.targets.map(_.map({ - case y: InstanceTarget => updateInstance(y) - case y: ReferenceTarget => updateReference(y) - case y => Some(y) - })) - if (newTargets.flatten.forall(_.isDefined)) Some(x.duplicate(newTargets.map(_.map(_.get)))) else None - case x => Some(x) - }) - .filter(_.isDefined) - .map(_.get) - ) - }) - .getOrElse(state.annotations) - - state.copy(circuit = newCircuit, renames = mainRename, annotations = newAnnotations) - } -} diff --git a/src/main/scala/barstools/tapeout/transforms/RemoveUnusedModules.scala b/src/main/scala/barstools/tapeout/transforms/RemoveUnusedModules.scala deleted file mode 100644 index 5d1cbc6c..00000000 --- a/src/main/scala/barstools/tapeout/transforms/RemoveUnusedModules.scala +++ /dev/null @@ -1,67 +0,0 @@ -// See LICENSE for license details. - -package barstools.tapeout.transforms - -import firrtl._ -import firrtl.annotations.ModuleTarget -import firrtl.ir._ -import firrtl.options.Dependency -import firrtl.passes.memlib.ReplSeqMem -import firrtl.stage.Forms -import firrtl.stage.TransformManager.TransformDependency - -// Removes all the unused modules in a circuit by recursing through every -// instance (starting at the main module) -class RemoveUnusedModules extends Transform with DependencyAPIMigration { - - override def prerequisites: Seq[TransformDependency] = Forms.HighForm - override def optionalPrerequisites: Seq[TransformDependency] = Seq.empty - override def optionalPrerequisiteOf: Seq[TransformDependency] = { - Forms.HighEmitters :+ Dependency[ReplSeqMem] - } - override def invalidates(a: Transform): Boolean = false - - 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 - - def getUsedModules(om: Option[Module]): Set[String] = { - om match { - case Some(m) => { - def someStatements(statement: Statement): Seq[Statement] = - statement match { - case b: Block => - b.stmts.map { someStatements(_) } - .foldLeft(Seq[Statement]())(_ ++ _) - case when: Conditionally => - someStatements(when.conseq) ++ someStatements(when.alt) - case i: DefInstance => Seq(i) - case _ => Seq() - } - - someStatements(m.body).map { - case s: DefInstance => Set(s.module) | getUsedModules(modulesByName(s.module)) - case _ => Set[String]() - }.foldLeft(Set(m.name))(_ | _) - } - - case None => Set.empty[String] - } - } - val usedModuleSet = getUsedModules(modulesByName(state.circuit.main)) - - val usedModuleSeq = state.circuit.modules.filter { usedModuleSet contains _.name } - val usedModuleNames = usedModuleSeq.map(_.name) - - val renames = state.renames.getOrElse(RenameMap()) - - state.circuit.modules.filterNot { usedModuleSet contains _.name }.foreach { x => - renames.record(ModuleTarget(state.circuit.main, x.name), Nil) - } - - val newCircuit = Circuit(state.circuit.info, usedModuleSeq, state.circuit.main) - state.copy(circuit = newCircuit, renames = Some(renames)) - } -} diff --git a/src/main/scala/barstools/tapeout/transforms/ResetInverter.scala b/src/main/scala/barstools/tapeout/transforms/ResetInverter.scala deleted file mode 100644 index 29c9f0da..00000000 --- a/src/main/scala/barstools/tapeout/transforms/ResetInverter.scala +++ /dev/null @@ -1,69 +0,0 @@ -// See LICENSE for license details. - -package barstools.tapeout.transforms - -import chisel3.experimental.RunFirrtlTransform -import firrtl.PrimOps.Not -import firrtl.annotations.{Annotation, CircuitName, ModuleName, SingleTargetAnnotation} -import firrtl.ir._ -import firrtl.passes.Pass -import firrtl.stage.Forms -import firrtl.stage.TransformManager.TransformDependency -import firrtl.{CircuitState, DependencyAPIMigration, Transform} - -case class ResetInverterAnnotation(target: ModuleName) extends SingleTargetAnnotation[ModuleName] { - override def duplicate(n: ModuleName): Annotation = ResetInverterAnnotation(n) -} - -object ResetN extends Pass { - private val Bool = UIntType(IntWidth(1)) - // Only works on Modules with a Bool port named reset - def invertReset(mod: Module): Module = { - // Check that it actually has reset - require(mod.ports.exists(p => p.name == "reset" && p.tpe == Bool), "Can only invert reset on a module with reset!") - // Rename "reset" to "reset_n" - val portsx = mod.ports.map { - case Port(info, "reset", Input, Bool) => - Port(info, "reset_n", Input, Bool) - case other => other - } - val newReset = DefNode(NoInfo, "reset", DoPrim(Not, Seq(Reference("reset_n", Bool)), Seq.empty, Bool)) - val bodyx = Block(Seq(newReset, mod.body)) - mod.copy(ports = portsx, body = bodyx) - } - - def run(c: Circuit): Circuit = { - c.copy(modules = c.modules.map { - case mod: Module if mod.name == c.main => invertReset(mod) - case other => other - }) - } -} - -class ResetInverterTransform extends Transform with DependencyAPIMigration { - - override def prerequisites: Seq[TransformDependency] = Forms.LowForm - override def optionalPrerequisites: Seq[TransformDependency] = Forms.LowFormOptimized - override def optionalPrerequisiteOf: Seq[TransformDependency] = Forms.LowEmitters - override def invalidates(a: Transform): Boolean = false - - override def execute(state: CircuitState): CircuitState = { - state.annotations.filter(_.isInstanceOf[ResetInverterAnnotation]) match { - case Nil => state - case Seq(ResetInverterAnnotation(ModuleName(state.circuit.main, CircuitName(_)))) => - state.copy(circuit = ResetN.run(state.circuit)) - case annotations => - throw new Exception(s"There should be only one InvertReset annotation: got ${annotations.mkString(" -- ")}") - } - } -} - -trait ResetInverter { - self: chisel3.Module => - def invert[T <: chisel3.Module](module: T): Unit = { - chisel3.experimental.annotate(new chisel3.experimental.ChiselAnnotation with RunFirrtlTransform { - def transformClass: Class[_ <: Transform] = classOf[ResetInverterTransform] - def toFirrtl: Annotation = ResetInverterAnnotation(module.toNamed) - }) - } -} diff --git a/src/main/scala/barstools/tapeout/transforms/stage/TapeoutStage.scala b/src/main/scala/barstools/tapeout/transforms/stage/TapeoutStage.scala index 7ab59717..8f3af9e3 100644 --- a/src/main/scala/barstools/tapeout/transforms/stage/TapeoutStage.scala +++ b/src/main/scala/barstools/tapeout/transforms/stage/TapeoutStage.scala @@ -4,6 +4,7 @@ package barstools.tapeout.transforms.stage import barstools.tapeout.transforms.GenerateModelStageMain import chisel3.stage.ChiselCli +import firrtl.stage.{RunFirrtlTransformAnnotation} import firrtl.AnnotationSeq import firrtl.annotations.{Annotation, NoTargetAnnotation} import firrtl.options.{HasShellOptions, Shell, ShellOption, Stage, Unserializable} @@ -27,12 +28,32 @@ object OutAnnoAnnotation extends HasShellOptions { ) } +case class CompilerNameAnnotation(name: String) extends NoTargetAnnotation with TapeoutOption + +// duplicate of firrtl.stage.CompilerAnnotation but needed so that you can have a +// CompilerAnnotation to match on when adding new transforms +object DuplicateCompilerAnnotation extends HasShellOptions { + val options: Seq[ShellOption[_]] = Seq( + new ShellOption[String]( + longOption = "duplicate-compiler", + shortOption = Some("DX"), + toAnnotationSeq = (s: String) => { + Seq( + CompilerNameAnnotation(s)) + }, + helpText = "duplicate-compiler", + helpValueName = Some("same as --compiler FIRRTL flag") + ) + ) +} + trait TapeoutCli { this: Shell => parser.note("Tapeout specific options") Seq( - OutAnnoAnnotation + OutAnnoAnnotation, + DuplicateCompilerAnnotation ).foreach(_.addOptions(parser)) }