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:
John Wright
2019-02-08 01:40:59 -08:00
committed by John Wright
parent c8efc5e88b
commit 79b8fd324b
3 changed files with 43 additions and 62 deletions

2
mdf

Submodule mdf updated: ee50cc2b09...c13e31656e

View File

@@ -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
}

View File

@@ -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))
}
}