[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:
David Biancolin 2019-10-10 00:03:58 -07:00 committed by GitHub
commit 54ad7d1420
6 changed files with 147 additions and 39 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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