[MIDAS] Merge pull request #148 from ucb-bar/runtime-conf-generation
Add a new Stage to Generate FASED Runtime Configs
This commit is contained in:
commit
54ad7d1420
|
@ -44,3 +44,18 @@ object ConfigStringAnnotation extends HasShellOptions {
|
|||
shortOption = Some("ggcs"),
|
||||
helpValueName = Some("<class name>{[_<additional class names>]}}") ) )
|
||||
}
|
||||
|
||||
// Used to specify the name of the desired runtime configuration
|
||||
// file. Will be emitted in the TargetDir
|
||||
case class RuntimeConfigNameAnnotation(configString: String) extends NoTargetAnnotation
|
||||
|
||||
object RuntimeConfigNameAnnotation extends HasShellOptions {
|
||||
|
||||
val options = Seq(
|
||||
new ShellOption[String](
|
||||
longOption = "golden-gate-runtime-config-name",
|
||||
toAnnotationSeq = (a: String) => Seq(RuntimeConfigNameAnnotation(a)),
|
||||
helpText = "Specifies the filename for the generated runtime configuration file.",
|
||||
shortOption = Some("ggrc"),
|
||||
helpValueName = Some("<filename>") ) )
|
||||
}
|
||||
|
|
|
@ -0,0 +1,46 @@
|
|||
// See LICENSE for license details.
|
||||
|
||||
package midas.stage
|
||||
|
||||
import freechips.rocketchip.config.{Parameters, Config}
|
||||
import freechips.rocketchip.util.{ParsedInputNames}
|
||||
|
||||
trait ConfigLookup {
|
||||
// This copies the rocketChip get config code, but adds support for looking up a config class
|
||||
// from one of many packages
|
||||
def getConfigWithFallback(packages: Seq[String], configNames: Seq[String]): Config = {
|
||||
// Recursively try to lookup config in a set of scala packages
|
||||
def getConfig(remainingPackages: Seq[String], configName: String): Config = remainingPackages match {
|
||||
// No fallback packages left
|
||||
case Nil => throw new Exception(
|
||||
s"""Unable to find class "$configName" in packages: "${packages.mkString(", ")}", did you misspell it?""")
|
||||
// Take the head of the package list, and check if there is a class with the matching name
|
||||
case configPackage :: oremainingPackages => {
|
||||
try {
|
||||
Class.forName(configPackage + "." + configName).newInstance.asInstanceOf[Config]
|
||||
} catch {
|
||||
case t: java.lang.ClassNotFoundException => getConfig(oremainingPackages, configName)
|
||||
}
|
||||
}
|
||||
}
|
||||
// For each config basename, look up the correct class from one of a
|
||||
// sequence of potential packages and concatenate them together to create
|
||||
// a complete parameterization space
|
||||
new Config(configNames.foldRight(Parameters.empty) { case (currentName, config) =>
|
||||
getConfig(packages, currentName) ++ config
|
||||
})
|
||||
}
|
||||
|
||||
// For host configurations, look up configs in one of three places:
|
||||
// 1) The user specified project (eg. firesim.firesim)
|
||||
// 2) firesim.configs -> Legacy SimConfigs
|
||||
// 3) firesim.util -> this has a bunch of target agnostic configurations, like host frequency
|
||||
// 4) midas -> This has debug features, etc
|
||||
// Allows the user to concatenate configs together from different packages
|
||||
// without needing to fully specify the class name for each config
|
||||
// eg. FireSimConfig_F90MHz maps to: firesim.util.F90MHz ++ firesim.firesim.FiresimConfig
|
||||
def getParameters(hostNames: ParsedInputNames): Parameters = {
|
||||
val packages = (hostNames.configProject +: Seq("firesim.configs", "firesim.util", "midas")).distinct
|
||||
new Config(getConfigWithFallback(packages, hostNames.configClasses))
|
||||
}
|
||||
}
|
|
@ -17,45 +17,7 @@ import freechips.rocketchip.util.{ParsedInputNames}
|
|||
import java.io.{File, FileWriter, Writer}
|
||||
import logger._
|
||||
|
||||
class GoldenGateCompilerPhase extends Phase {
|
||||
|
||||
// This copies the rocketChip get config code, but adds support for looking up a config class
|
||||
// from one of many packages
|
||||
def getConfigWithFallback(packages: Seq[String], configNames: Seq[String]): Config = {
|
||||
// Recursively try to lookup config in a set of scala packages
|
||||
def getConfig(remainingPackages: Seq[String], configName: String): Config = remainingPackages match {
|
||||
// No fallback packages left
|
||||
case Nil => throw new Exception(
|
||||
s"""Unable to find class "$configName" in packages: "${packages.mkString(", ")}", did you misspell it?""")
|
||||
// Take the head of the package list, and check if there is a class with the matching name
|
||||
case configPackage :: oremainingPackages => {
|
||||
try {
|
||||
Class.forName(configPackage + "." + configName).newInstance.asInstanceOf[Config]
|
||||
} catch {
|
||||
case t: java.lang.ClassNotFoundException => getConfig(oremainingPackages, configName)
|
||||
}
|
||||
}
|
||||
}
|
||||
// For each config basename, look up the correct class from one of a
|
||||
// sequence of potential packages and concatenate them together to create
|
||||
// a complete parameterization space
|
||||
new Config(configNames.foldRight(Parameters.empty) { case (currentName, config) =>
|
||||
getConfig(packages, currentName) ++ config
|
||||
})
|
||||
}
|
||||
|
||||
// For host configurations, look up configs in one of three places:
|
||||
// 1) The user specified project (eg. firesim.firesim)
|
||||
// 2) firesim.configs -> Legacy SimConfigs
|
||||
// 3) firesim.util -> this has a bunch of target agnostic configurations, like host frequency
|
||||
// 4) midas -> This has debug features, etc
|
||||
// Allows the user to concatenate configs together from different packages
|
||||
// without needing to fully specify the class name for each config
|
||||
// eg. FireSimConfig_F90MHz maps to: firesim.util.F90MHz ++ firesim.firesim.FiresimConfig
|
||||
def getParameters(hostNames: ParsedInputNames): Parameters = {
|
||||
val packages = (hostNames.configProject +: Seq("firesim.configs", "firesim.util", "midas")).distinct
|
||||
new Config(getConfigWithFallback(packages, hostNames.configClasses))
|
||||
}
|
||||
class GoldenGateCompilerPhase extends Phase with ConfigLookup {
|
||||
|
||||
def transform(annotations: AnnotationSeq): AnnotationSeq = {
|
||||
val allCircuits = annotations.collect({ case FirrtlCircuitAnnotation(circuit) => circuit })
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
// See LICENSE for license details.
|
||||
|
||||
package midas.stage
|
||||
|
||||
import midas.{OutputDir}
|
||||
import midas.widgets.{SerializableBridgeAnnotation}
|
||||
|
||||
import freechips.rocketchip.util.{ParsedInputNames}
|
||||
|
||||
import firrtl.{Transform, CircuitState, AnnotationSeq}
|
||||
import firrtl.options.{Phase, TargetDirAnnotation}
|
||||
|
||||
import java.io.{File, FileWriter, Writer}
|
||||
import logger._
|
||||
|
||||
class RuntimeConfigGenerationPhase extends Phase with ConfigLookup {
|
||||
|
||||
def transform(annotations: AnnotationSeq): AnnotationSeq = {
|
||||
val targetDir = annotations.collectFirst({ case TargetDirAnnotation(targetDir) => new File(targetDir) }).get
|
||||
val configPackage = annotations.collectFirst({ case ConfigPackageAnnotation(p) => p }).get
|
||||
val configString = annotations.collectFirst({ case ConfigStringAnnotation(s) => s }).get
|
||||
val runtimeConfigName = annotations.collectFirst({ case RuntimeConfigNameAnnotation(s) => s }).get
|
||||
|
||||
val pNames = ParsedInputNames("UNUSED", "UNUSED", "UNUSED", configPackage, configString)
|
||||
|
||||
implicit val p = getParameters(pNames).alterPartial({
|
||||
case OutputDir => targetDir
|
||||
})
|
||||
|
||||
val fasedBridgeAnnos = annotations.collect({
|
||||
case anno @ SerializableBridgeAnnotation(_,_,className,_)
|
||||
if className == classOf[midas.models.FASEDMemoryTimingModel].getName => anno
|
||||
})
|
||||
// Since presently all memory models share the same runtime configuration. Grab only the first
|
||||
// FASED BridgeAnnotation, and use that to elaborate a memory model
|
||||
fasedBridgeAnnos.headOption.map({ anno =>
|
||||
// Here we're spoofing elaboration that occurs in FPGATop, which assumes ExtractBridges has been run
|
||||
lazy val memModel = anno.toIOAnnotation("").elaborateWidget.asInstanceOf[midas.models.FASEDMemoryTimingModel]
|
||||
chisel3.Driver.elaborate(() => memModel)
|
||||
memModel.getSettings(runtimeConfigName)
|
||||
})
|
||||
annotations
|
||||
}
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
// See LICENSE for license details.
|
||||
|
||||
package midas.stage
|
||||
|
||||
import firrtl.options.Shell
|
||||
|
||||
trait RuntimeConfigGeneratorCli { this: Shell =>
|
||||
parser.note("Golden Gate Runtime Configuration Generator Options")
|
||||
Seq(GoldenGateInputAnnotationFileAnnotation,
|
||||
ConfigPackageAnnotation,
|
||||
ConfigStringAnnotation,
|
||||
RuntimeConfigNameAnnotation
|
||||
)
|
||||
.map(_.addOptions(parser))
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
// See LICENSE for license details.
|
||||
|
||||
package midas.stage
|
||||
|
||||
import firrtl.AnnotationSeq
|
||||
import firrtl.options.{Phase, PhaseManager, PreservesAll, Shell, Stage, StageMain}
|
||||
import firrtl.options.phases.DeletedWrapper
|
||||
import firrtl.options.Viewer.view
|
||||
|
||||
import java.io.{StringWriter, PrintWriter}
|
||||
|
||||
class RuntimeConfigGeneratorStage extends Stage with PreservesAll[Phase] {
|
||||
val shell: Shell = new Shell("confgen") with RuntimeConfigGeneratorCli
|
||||
|
||||
private val phases: Seq[Phase] =
|
||||
Seq(
|
||||
new GoldenGateGetIncludes,
|
||||
new firrtl.stage.phases.AddDefaults,
|
||||
new midas.stage.RuntimeConfigGenerationPhase)
|
||||
.map(DeletedWrapper(_))
|
||||
|
||||
|
||||
def run(annotations: AnnotationSeq): AnnotationSeq = phases.foldLeft(annotations)((a, f) => f.transform(a))
|
||||
}
|
||||
|
||||
object RuntimeConfigGeneratorMain extends StageMain(new RuntimeConfigGeneratorStage)
|
Loading…
Reference in New Issue