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.
This commit is contained in:
2
mdf
2
mdf
Submodule mdf updated: ee50cc2b09...c13e31656e
@@ -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
|
||||
}
|
||||
|
||||
@@ -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))
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user