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 net.jcazevedo.moultingyaml._
|
||||||
import com.typesafe.scalalogging.LazyLogging
|
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 =>
|
trait HasTapeoutOptions { self: ExecutionOptionsManager with HasFirrtlOptions =>
|
||||||
var tapeoutOptions = TapeoutOptions()
|
var tapeoutOptions = TapeoutOptions()
|
||||||
|
|
||||||
@@ -61,7 +48,6 @@ trait HasTapeoutOptions { self: ExecutionOptionsManager with HasFirrtlOptions =>
|
|||||||
"use this to set harnessTop"
|
"use this to set harnessTop"
|
||||||
}
|
}
|
||||||
|
|
||||||
parser.note("")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
case class TapeoutOptions(
|
case class TapeoutOptions(
|
||||||
@@ -73,75 +59,66 @@ case class TapeoutOptions(
|
|||||||
// Requires two phases, one to collect modules below synTop in the hierarchy
|
// Requires two phases, one to collect modules below synTop in the hierarchy
|
||||||
// and a second to remove those modules to generate the test harness
|
// and a second to remove those modules to generate the test harness
|
||||||
sealed trait GenerateTopAndHarnessApp extends LazyLogging { this: App =>
|
sealed trait GenerateTopAndHarnessApp extends LazyLogging { this: App =>
|
||||||
def getOptionsManager = {
|
lazy val optionsManager = {
|
||||||
val optionsManager = new ExecutionOptionsManager("tapeout") with HasFirrtlOptions with HasTapeoutOptions
|
val optionsManager = new ExecutionOptionsManager("tapeout") with HasFirrtlOptions with HasTapeoutOptions
|
||||||
if (!optionsManager.parse(args)) {
|
if (!optionsManager.parse(args)) {
|
||||||
throw new Exception("Error parsing options!")
|
throw new Exception("Error parsing options!")
|
||||||
}
|
}
|
||||||
optionsManager
|
optionsManager
|
||||||
}
|
}
|
||||||
lazy val optionsManager = getOptionsManager
|
|
||||||
lazy val tapeoutOptions = optionsManager.tapeoutOptions
|
lazy val tapeoutOptions = optionsManager.tapeoutOptions
|
||||||
// Tapeout options
|
// Tapeout options
|
||||||
lazy val harnessOutput = tapeoutOptions.harnessOutput
|
|
||||||
lazy val synTop = tapeoutOptions.synTop
|
lazy val synTop = tapeoutOptions.synTop
|
||||||
lazy val harnessTop = tapeoutOptions.harnessTop
|
lazy val harnessTop = tapeoutOptions.harnessTop
|
||||||
|
|
||||||
lazy val firrtlOptions = optionsManager.firrtlOptions
|
lazy val firrtlOptions = optionsManager.firrtlOptions
|
||||||
// FIRRTL options
|
// FIRRTL options
|
||||||
lazy val annoFiles = firrtlOptions.annotationFileNames
|
lazy val annoFiles = firrtlOptions.annotationFileNames
|
||||||
|
|
||||||
private def getFirstPhasePasses: Seq[Transform] = {
|
private def topTransforms: Seq[Transform] = {
|
||||||
Seq(
|
Seq(
|
||||||
new ReParentCircuit(synTop.get),
|
new ReParentCircuit(synTop.get),
|
||||||
new RemoveUnusedModules
|
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(
|
Seq(
|
||||||
new ConvertToExtMod((m) => m.name == synTop.get),
|
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 RemoveUnusedModules,
|
||||||
new RenameModulesAndInstances((m) => AllModules.rename(m, "_in" + harnessTop.get)),
|
new RenameModulesAndInstances((old) => if (externals contains old) old else (old + "_in" + harnessTop.get))
|
||||||
new RemoveUnusedModules
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Top Generation
|
// Top Generation
|
||||||
protected def firstPhase: Unit = {
|
protected def executeTop: Unit = {
|
||||||
|
|
||||||
val firstPhaseOptions = getOptionsManager
|
optionsManager.firrtlOptions = optionsManager.firrtlOptions.copy(
|
||||||
firstPhaseOptions.firrtlOptions = firstPhaseOptions.firrtlOptions.copy(
|
customTransforms = firrtlOptions.customTransforms ++ topTransforms
|
||||||
customTransforms = firrtlOptions.customTransforms ++ getFirstPhasePasses
|
|
||||||
)
|
)
|
||||||
|
|
||||||
firrtl.Driver.execute(firstPhaseOptions)
|
firrtl.Driver.execute(optionsManager)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Harness Generation
|
// Harness Generation
|
||||||
protected def secondPhase: Unit = {
|
protected def executeHarness: Unit = {
|
||||||
val secondPhaseOptions = getOptionsManager
|
|
||||||
secondPhaseOptions.firrtlOptions = secondPhaseOptions.firrtlOptions.copy(
|
optionsManager.firrtlOptions = optionsManager.firrtlOptions.copy(
|
||||||
outputFileNameOverride = harnessOutput.get,
|
customTransforms = harnessTransforms
|
||||||
customTransforms = getSecondPhasePasses
|
|
||||||
)
|
)
|
||||||
|
|
||||||
firrtl.Driver.execute(secondPhaseOptions)
|
firrtl.Driver.execute(optionsManager)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
object GenerateTop extends App with GenerateTopAndHarnessApp {
|
object GenerateTop extends App with GenerateTopAndHarnessApp {
|
||||||
// Only need a single phase to generate the top module
|
// Only need a single phase to generate the top module
|
||||||
firstPhase
|
executeTop
|
||||||
}
|
}
|
||||||
|
|
||||||
object GenerateHarness extends App with GenerateTopAndHarnessApp {
|
object GenerateHarness extends App with GenerateTopAndHarnessApp {
|
||||||
// Do minimal work for the first phase to generate test harness
|
// Do minimal work for the first phase to generate test harness
|
||||||
secondPhase
|
executeHarness
|
||||||
}
|
|
||||||
|
|
||||||
object GenerateTopAndHarness extends App with GenerateTopAndHarnessApp {
|
|
||||||
// Do everything, top and harness generation
|
|
||||||
firstPhase
|
|
||||||
secondPhase
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,13 +5,15 @@ package barstools.tapeout.transforms
|
|||||||
import firrtl._
|
import firrtl._
|
||||||
import firrtl.ir._
|
import firrtl.ir._
|
||||||
import firrtl.passes.Pass
|
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
|
class RemoveUnusedModules extends Transform {
|
||||||
// instance (starting at the main module)
|
def inputForm = MidForm
|
||||||
class RemoveUnusedModulesPass extends Pass {
|
def outputForm = MidForm
|
||||||
|
|
||||||
def run(c: Circuit): Circuit = {
|
def execute(state: CircuitState): CircuitState = {
|
||||||
val modulesByName = c.modules.map{
|
val modulesByName = state.circuit.modules.map{
|
||||||
case m: Module => (m.name, Some(m))
|
case m: Module => (m.name, Some(m))
|
||||||
case m: ExtModule => (m.name, None)
|
case m: ExtModule => (m.name, None)
|
||||||
}.toMap
|
}.toMap
|
||||||
@@ -39,21 +41,23 @@ class RemoveUnusedModulesPass extends Pass {
|
|||||||
case None => Set.empty[String]
|
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)
|
val renames = state.renames.getOrElse(RenameMap())
|
||||||
}
|
|
||||||
}
|
//state.circuit.modules.filterNot { usedModuleSet contains _.name } foreach { x => renames.record(ModuleTarget(state.circuit.main, x.name), Seq()) }
|
||||||
|
|
||||||
class RemoveUnusedModules extends Transform with SeqTransformBased {
|
val newCircuit = Circuit(state.circuit.info, usedModuleSeq, state.circuit.main)
|
||||||
def inputForm = MidForm
|
val newAnnos = AnnotationSeq(state.annotations.toSeq.filter { _ match {
|
||||||
def outputForm = MidForm
|
// XXX This is wrong, but it works for now
|
||||||
def transforms = Seq(new RemoveUnusedModulesPass)
|
case x: DontTouchAnnotation => false
|
||||||
|
//case x: DontTouchAnnotation => usedModuleNames contains x.target.module
|
||||||
def execute(state: CircuitState): CircuitState = {
|
case _ => true
|
||||||
val ret = runTransforms(state)
|
}})
|
||||||
CircuitState(ret.circuit, outputForm, ret.annotations, ret.renames)
|
|
||||||
|
CircuitState(newCircuit, outputForm, newAnnos, Some(renames))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user