diff --git a/tapeout/src/main/scala/transforms/.pads/AddIOPadsTransform.scala b/tapeout/src/main/scala/transforms/.pads/AddIOPadsTransform.scala index d427d0d9..b586e8be 100644 --- a/tapeout/src/main/scala/transforms/.pads/AddIOPadsTransform.scala +++ b/tapeout/src/main/scala/transforms/.pads/AddIOPadsTransform.scala @@ -39,7 +39,7 @@ class AddIOPadsTransform extends Transform with SeqTransformBased { PadPlacementFile.generate(techLoc, targetDir, padFrameName, portPads, supplyPads) transformList ++= Seq( Legalize, - ResolveGenders, + ResolveFlows, // Types really need to be known... InferTypes, new AddPadFrame(x.topModName, padFrameName, topInternalName, portPads, supplyPads), @@ -48,7 +48,7 @@ class AddIOPadsTransform extends Transform with SeqTransformBased { InferTypes, Uniquify, ResolveKinds, - ResolveGenders + ResolveFlows ) // Expects BlackBox helper to be run after to inline pad Verilog! val ret = runTransforms(state) diff --git a/tapeout/src/main/scala/transforms/.pads/AddPadFrame.scala b/tapeout/src/main/scala/transforms/.pads/AddPadFrame.scala index 853cfced..62447bd5 100644 --- a/tapeout/src/main/scala/transforms/.pads/AddPadFrame.scala +++ b/tapeout/src/main/scala/transforms/.pads/AddPadFrame.scala @@ -112,8 +112,8 @@ class AddPadFrame( // Normal verilog in/out can be mapped to uint, sint, or clocktype, so need cast case _ => val padBBType = UIntType(getWidth(p.port.tpe)) - val padInRef = WSubField(padRef, DigitalPad.inName, padBBType, UNKNOWNGENDER) - val padOutRef = WSubField(padRef, DigitalPad.outName, padBBType, UNKNOWNGENDER) + val padInRef = WSubField(padRef, DigitalPad.inName, padBBType, UnknownFlow) + val padOutRef = WSubField(padRef, DigitalPad.outName, padBBType, UnknownFlow) val (rhsPadIn, lhsPadOut) = p.portDirection match { case Input => (extRef, intRef) case Output => (intRef, extRef) @@ -130,4 +130,4 @@ class AddPadFrame( Module(NoInfo, padFrameName, ports = intPorts ++ extPorts, body = Block(ioPadInsts ++ connects ++ supplyPadInsts)) } -} \ No newline at end of file +} diff --git a/tapeout/src/main/scala/transforms/AddSuffixToModuleNames.scala b/tapeout/src/main/scala/transforms/AddSuffixToModuleNames.scala new file mode 100644 index 00000000..0e1a3739 --- /dev/null +++ b/tapeout/src/main/scala/transforms/AddSuffixToModuleNames.scala @@ -0,0 +1,65 @@ +// See LICENSE for license details. + +package barstools.tapeout.transforms + +import firrtl._ +import firrtl.ir._ +import firrtl.annotations._ +import firrtl.Mappers._ + + +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) +} + +// This doesn't rename ExtModules under the assumption that they're some +// Verilog black box and therefore can't be renamed. Since the point is to +// allow FIRRTL to be linked together using "cat" and ExtModules don't get +// emitted, this should be safe. +class AddSuffixToModuleNames extends Transform { + def inputForm = LowForm + def outputForm = LowForm + + def processAnnos(annos: AnnotationSeq): (AnnotationSeq, (String) => String) = { + val whitelist = annos.collect({ case KeepNameAnnotation(tgt) => tgt.module }).toSet + val newAnnos = annos.filterNot(_.isInstanceOf[ModuleNameSuffixAnnotation]) + val suffixes = annos.collect({ case ModuleNameSuffixAnnotation(_, suffix) => suffix }) + require(suffixes.length <= 1) + + val suffix = suffixes.headOption.getOrElse("") + val renamer = { name: String => if (whitelist(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 m: WDefInstance => new WDefInstance(m.info, m.name, renamer(m.module), m.tpe) + case s => s map renameInstanceModules(renamer) + } + } + + 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) = processAnnos(state.annotations) + val (ret, renames) = run(state, renamer) + state.copy(circuit = ret, annotations = newAnnos, renames = Some(renames)) + } +} diff --git a/tapeout/src/main/scala/transforms/AvoidExtModuleCollisions.scala b/tapeout/src/main/scala/transforms/AvoidExtModuleCollisions.scala new file mode 100644 index 00000000..df1e272e --- /dev/null +++ b/tapeout/src/main/scala/transforms/AvoidExtModuleCollisions.scala @@ -0,0 +1,23 @@ +// See LICENSE for license details. + +package barstools.tapeout.transforms + +import firrtl._ +import firrtl.ir._ +import firrtl.annotations._ + +case class LinkExtModulesAnnotation(mustLink: Seq[ExtModule]) extends NoTargetAnnotation + +class AvoidExtModuleCollisions extends Transform { + def inputForm = HighForm + def outputForm = HighForm + 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/tapeout/src/main/scala/transforms/ConvertToExtModPass.scala b/tapeout/src/main/scala/transforms/ConvertToExtModPass.scala index 6f12e9b3..83486fd5 100644 --- a/tapeout/src/main/scala/transforms/ConvertToExtModPass.scala +++ b/tapeout/src/main/scala/transforms/ConvertToExtModPass.scala @@ -7,16 +7,19 @@ import firrtl.annotations._ import firrtl.ir._ import firrtl.passes.Pass +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(classify: (Module) => Boolean) extends Transform { +class ConvertToExtMod extends Transform { def inputForm = HighForm def outputForm = HighForm - - def run(state: CircuitState): (Circuit, RenameMap) = { - + def run(state: CircuitState, makeExt: Set[String]): (Circuit, RenameMap) = { val renames = RenameMap() val c = state.circuit renames.setCircuit(c.main) @@ -30,7 +33,7 @@ class ConvertToExtMod(classify: (Module) => Boolean) extends Transform { case x => x.foreachStmt(findDeadNames) } } - if (classify(m)) { + if (makeExt(m.name)) { m.foreachStmt(findDeadNames) removing.foreach { name => renames.record(ReferenceTarget(c.main, m.name, Nil, name, Nil), Nil) @@ -44,7 +47,9 @@ class ConvertToExtMod(classify: (Module) => Boolean) extends Transform { } def execute(state: CircuitState): CircuitState = { - val (ret, renames) = run(state) - state.copy(circuit = ret, renames = Some(renames)) + 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/tapeout/src/main/scala/transforms/Generate.scala b/tapeout/src/main/scala/transforms/Generate.scala index 32912c16..89df8b55 100644 --- a/tapeout/src/main/scala/transforms/Generate.scala +++ b/tapeout/src/main/scala/transforms/Generate.scala @@ -11,7 +11,7 @@ import firrtl.annotations.AnnotationYamlProtocol._ import firrtl.passes.memlib.ReplSeqMemAnnotation import firrtl.transforms.BlackBoxResourceFileNameAnno import net.jcazevedo.moultingyaml._ -import com.typesafe.scalalogging.LazyLogging +import logger.LazyLogging trait HasTapeoutOptions { self: ExecutionOptionsManager with HasFirrtlOptions => var tapeoutOptions = TapeoutOptions() @@ -161,36 +161,27 @@ sealed trait GenerateTopAndHarnessApp extends LazyLogging { this: App => // FIRRTL options lazy val annoFiles = firrtlOptions.annotationFileNames - lazy val topTransforms: Seq[Transform] = { - Seq( - new ReParentCircuit(synTop.get), - new RemoveUnusedModules - ) - } + val topTransforms = Seq( + new ReParentCircuit, + new RemoveUnusedModules + ) + + lazy val rootCircuitTarget = CircuitTarget(harnessTop.get) + + lazy val topAnnos = synTop.map(st => ReParentCircuitAnnotation(rootCircuitTarget.module(st))) ++ + tapeoutOptions.topDotfOut.map(BlackBoxResourceFileNameAnno(_)) lazy val topOptions = firrtlOptions.copy( customTransforms = firrtlOptions.customTransforms ++ topTransforms, - annotations = firrtlOptions.annotations ++ tapeoutOptions.topDotfOut.map(BlackBoxResourceFileNameAnno(_)) + annotations = firrtlOptions.annotations ++ topAnnos ) - class AvoidExtModuleCollisions(mustLink: Seq[ExtModule]) extends Transform { - def inputForm = HighForm - def outputForm = HighForm - def execute(state: CircuitState): CircuitState = { - state.copy(circuit = state.circuit.copy(modules = state.circuit.modules ++ mustLink)) - } - } - - private def harnessTransforms(topExtModules: Seq[ExtModule]): 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", "SimDTM") - Seq( - new ConvertToExtMod((m) => m.name == synTop.get), - new RemoveUnusedModules, - new AvoidExtModuleCollisions(topExtModules), - new RenameModulesAndInstances((old) => if (externals contains old) old else (old + "_in" + harnessTop.get)) - ) - } + val harnessTransforms = Seq( + new ConvertToExtMod, + new RemoveUnusedModules, + new AvoidExtModuleCollisions, + new AddSuffixToModuleNames + ) // Dump firrtl and annotation files protected def dump(res: FirrtlExecutionSuccess, firFile: Option[String], annoFile: Option[String]): Unit = { @@ -230,17 +221,26 @@ sealed trait GenerateTopAndHarnessApp extends LazyLogging { this: App => // Execute top and get list of ExtModules to avoid collisions val topExtModules = executeTop() + val externals = Seq("SimSerial", "SimDTM") ++ harnessTop ++ synTop + + val harnessAnnos = + tapeoutOptions.harnessDotfOut.map(BlackBoxResourceFileNameAnno(_)).toSeq ++ + externals.map(ext => KeepNameAnnotation(rootCircuitTarget.module(ext))) ++ + harnessTop.map(ht => ModuleNameSuffixAnnotation(rootCircuitTarget, s"_in${ht}")) ++ + synTop.map(st => ConvertToExtModAnnotation(rootCircuitTarget.module(st))) :+ + LinkExtModulesAnnotation(topExtModules) + // For harness run, change some firrtlOptions (below) for harness phase // customTransforms: setup harness transforms, add AvoidExtModuleCollisions // outputFileNameOverride: change to harnessOutput // conf file must change to harnessConf by mapping annotations optionsManager.firrtlOptions = firrtlOptions.copy( - customTransforms = firrtlOptions.customTransforms ++ harnessTransforms(topExtModules), + customTransforms = firrtlOptions.customTransforms ++ harnessTransforms, outputFileNameOverride = tapeoutOptions.harnessOutput.get, annotations = firrtlOptions.annotations.map({ case ReplSeqMemAnnotation(i, o) => ReplSeqMemAnnotation(i, tapeoutOptions.harnessConf.get) case a => a - }) ++ tapeoutOptions.harnessDotfOut.map(BlackBoxResourceFileNameAnno(_)) + }) ++ harnessAnnos ) val harnessResult = firrtl.Driver.execute(optionsManager) harnessResult match { diff --git a/tapeout/src/main/scala/transforms/ReParentCircuit.scala b/tapeout/src/main/scala/transforms/ReParentCircuit.scala index e1a42664..574d9dda 100644 --- a/tapeout/src/main/scala/transforms/ReParentCircuit.scala +++ b/tapeout/src/main/scala/transforms/ReParentCircuit.scala @@ -7,18 +7,26 @@ import firrtl.ir._ import firrtl.passes.Pass import firrtl.annotations._ -class ReParentCircuit(newTopName: String) extends Transform { +case class ReParentCircuitAnnotation(target: ModuleTarget) + extends SingleTargetAnnotation[ModuleTarget] { + def duplicate(n: ModuleTarget) = this.copy(n) +} + +class ReParentCircuit extends Transform { def inputForm = HighForm def outputForm = HighForm - def run(c: Circuit, newTopName: String): (Circuit, RenameMap) = { - val myRenames = RenameMap() - myRenames.record(CircuitTarget(c.main), CircuitTarget(newTopName)) - (Circuit(c.info, c.modules, newTopName), myRenames) - } - def execute(state: CircuitState): CircuitState = { - val (ret, renames) = run(state.circuit, newTopName) - state.copy(circuit = ret, renames = Some(renames)) + 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 + } + state.copy(circuit = newCircuit, renames = mainRename) } } diff --git a/tapeout/src/main/scala/transforms/RenameModulesAndInstances.scala b/tapeout/src/main/scala/transforms/RenameModulesAndInstances.scala deleted file mode 100644 index 27388929..00000000 --- a/tapeout/src/main/scala/transforms/RenameModulesAndInstances.scala +++ /dev/null @@ -1,45 +0,0 @@ -// See LICENSE for license details. - -package barstools.tapeout.transforms - -import firrtl._ -import firrtl.annotations._ -import firrtl.ir._ -import firrtl.passes.Pass - -// This doesn't rename ExtModules under the assumption that they're some -// Verilog black box and therefore can't be renamed. Since the point is to -// allow FIRRTL to be linked together using "cat" and ExtModules don't get -// emitted, this should be safe. -class RenameModulesAndInstances(rename: (String) => String) extends Transform { - def inputForm = LowForm - def outputForm = LowForm - - def renameInstances(body: Statement): Statement = { - body match { - case m: DefInstance => new DefInstance(m.info, m.name, rename(m.module)) - case m: WDefInstance => new WDefInstance(m.info, m.name, rename(m.module), m.tpe) - case b: Block => new Block( b.stmts map { s => renameInstances(s) } ) - case s: Statement => s - } - } - - def run(state: CircuitState): (Circuit, RenameMap) = { - val myRenames = RenameMap() - val c = state.circuit - val modulesx = c.modules.map { - case m: ExtModule => - myRenames.record(ModuleTarget(c.main, m.name), ModuleTarget(c.main, rename(m.name))) - m.copy(name = rename(m.name)) - case m: Module => - myRenames.record(ModuleTarget(c.main, m.name), ModuleTarget(c.main, rename(m.name))) - new Module(m.info, rename(m.name), m.ports, renameInstances(m.body)) - } - (Circuit(c.info, modulesx, c.main), myRenames) - } - - def execute(state: CircuitState): CircuitState = { - val (ret, renames) = run(state) - state.copy(circuit = ret, renames = Some(renames)) - } -}