Use config to manage core registration and custom tests
This commit is contained in:
@@ -23,8 +23,7 @@ import sifive.blocks.devices.uart._
|
||||
import sifive.blocks.devices.spi._
|
||||
|
||||
import chipyard.{BuildTop, BuildSystem}
|
||||
import chipyard.TilesKey
|
||||
import chipyard.TileSeq._
|
||||
import chipyard.{GenericTilesKey, GenericTileConfig}
|
||||
|
||||
/**
|
||||
* TODO: Why do we need this?
|
||||
@@ -61,8 +60,8 @@ class WithSPIFlash(size: BigInt = 0x10000000) extends Config((site, here, up) =>
|
||||
SPIFlashParams(rAddress = 0x10040000, fAddress = 0x20000000, fSize = size))
|
||||
})
|
||||
|
||||
class WithL2TLBs(entries: Int) extends Config((site, here, up) => {
|
||||
case TilesKey(tilesKey) => up(tilesKey) tileMap (tile => tile.copy(
|
||||
class WithL2TLBs(entries: Int) extends GenericTileConfig((site, here, up) => {
|
||||
case GenericTilesKey(key) => up(GenericTilesKey(key)) map (tile => tile.copy(
|
||||
core = tile.core.copy(nL2TLBEntries = entries)
|
||||
))
|
||||
})
|
||||
@@ -150,4 +149,4 @@ class WithTraceIO extends Config((site, here, up) => {
|
||||
case BoomTilesKey => up(BoomTilesKey) map (tile => tile.copy(trace = true))
|
||||
case ArianeTilesKey => up(ArianeTilesKey) map (tile => tile.copy(trace = true))
|
||||
case TracePortKey => Some(TracePortParams())
|
||||
})
|
||||
})
|
||||
|
||||
@@ -15,6 +15,21 @@ import freechips.rocketchip.tile._
|
||||
import boom.common.{BoomTile, BoomTilesKey, BoomCrossingKey, BoomTileParams}
|
||||
import ariane.{ArianeTile, ArianeTilesKey, ArianeCrossingKey, ArianeTileParams}
|
||||
|
||||
case object CoreEntryKey extends Field[Seq[CoreEntryBase]](Nil)
|
||||
|
||||
// If this key is encountered by a GenericTilesKey extractor, throw immediately
|
||||
// Inside the body of GenericTileConfig, suppressed will be set to true to prevent the extractor from throwing
|
||||
case class GenericTilesKeyChecker(suppressed: Boolean) extends Field[Int](0)
|
||||
case class GenericTilesKeyImp(key: Field[Seq[TileParams]]) extends Field[Seq[GenericTileParams]](Nil)
|
||||
object GenericTilesKey {
|
||||
def apply(key: Field[Seq[TileParams]]) = GenericTilesKeyImp(key)
|
||||
def unapply(key: Any): Option[Field[Seq[TileParams]]] = key match {
|
||||
case GenericTilesKeyChecker(suppressed) if !suppressed => throw new Exception("GenericTilesKey must be in GenericTilesConfig")
|
||||
case GenericTilesKeyImp(key) => Some(key)
|
||||
case _ => None
|
||||
}
|
||||
}
|
||||
|
||||
// Base trait for all third-party core entries
|
||||
sealed trait CoreEntryBase {
|
||||
val name: String
|
||||
@@ -45,6 +60,11 @@ class CoreEntry[TileParamsT <: TileParams with Product: TypeTag, TileT <: BaseTi
|
||||
// Instantiate a tile and zip it with its parameter info, used by subsystem
|
||||
def instantiateTile(crossingLookup: (Seq[RocketCrossingParams], Int) => Seq[RocketCrossingParams], logicalTreeNode: LogicalTreeNode)
|
||||
(implicit p: Parameters, valName: ValName) = {
|
||||
// Sanity check of GenericTilesKey outside of GenericTileConfig
|
||||
// People would shoot themselves in the foot easily with this design, so a sanity check is necessary
|
||||
// Simply trigger the exception by looking up the checker key
|
||||
p(GenericTilesKeyChecker(false))
|
||||
|
||||
val tileParams = p(tilesKey)
|
||||
val crossings = crossingLookup(p(crossingKey), tileParams.size)
|
||||
(tileParams zip crossings) map {
|
||||
@@ -63,12 +83,41 @@ class CoreEntry[TileParamsT <: TileParams with Product: TypeTag, TileT <: BaseTi
|
||||
}
|
||||
}
|
||||
|
||||
// Config fragment to register a core
|
||||
class RegisterCore[TileParamsT <: TileParams with Product: TypeTag, TileT <: BaseTile : TypeTag](
|
||||
name: String,
|
||||
tilesKey: Field[Seq[TileParamsT]],
|
||||
crossingKey: Field[Seq[RocketCrossingParams]]
|
||||
) extends Config((site, here, up) => {
|
||||
case CoreEntryKey => new CoreEntry[TileParamsT, TileT](name, tilesKey, crossingKey) +: up(CoreEntryKey)
|
||||
})
|
||||
|
||||
// The config used along with GenericTilesKey.
|
||||
// It change a lookup for registered tile parameter into a lookup with GenericTilesKey in the function body temporarily.
|
||||
class GenericTileConfig(f: (View, View, View) => PartialFunction[Any, Any]) extends Config(
|
||||
new Config((site, here, up) => {
|
||||
case GenericTilesKeyChecker(_) => up(GenericTilesKeyChecker(true))
|
||||
case key if CoreManager.keyMatch(up, key) => up(GenericTilesKey(key.asInstanceOf[Field[Seq[TileParams]]])) map (t => t.convert)
|
||||
}) ++
|
||||
new Config(f) ++
|
||||
new Config((site, here, up) => {
|
||||
case GenericTilesKeyChecker(_) => up(GenericTilesKeyChecker(false))
|
||||
case GenericTilesKey(key) => up(key) map (t => new GenericTileParams(t))
|
||||
})
|
||||
)
|
||||
|
||||
// A list of all cores.
|
||||
object CoreManager {
|
||||
val cores: List[CoreEntryBase] = List(
|
||||
// TODO ADD YOUR CORE DEFINITION HERE; note that the
|
||||
// Built-in cores.
|
||||
val base_cores: List[CoreEntryBase] = List(
|
||||
new CoreEntry[RocketTileParams, RocketTile]("Rocket", RocketTilesKey, RocketCrossingKey),
|
||||
new CoreEntry[BoomTileParams, BoomTile]("Boom", BoomTilesKey, BoomCrossingKey),
|
||||
new CoreEntry[ArianeTileParams, ArianeTile]("Ariane", ArianeTilesKey, ArianeCrossingKey)
|
||||
)
|
||||
|
||||
// Look up all cores that are registered in the current config view.
|
||||
def cores(view: View): Seq[CoreEntryBase] = view(CoreEntryKey) ++ base_cores
|
||||
|
||||
// Check if the key is among the currently registered cores.
|
||||
def keyMatch(view: View, key: Any) = (cores(view) filter (c => c.keyEqual(key))).size != 0
|
||||
}
|
||||
|
||||
@@ -15,6 +15,36 @@ import freechips.rocketchip.tile._
|
||||
import boom.common.{BoomTile, BoomTilesKey, BoomCrossingKey, BoomTileParams}
|
||||
import ariane.{ArianeTile, ArianeTilesKey, ArianeCrossingKey, ArianeTileParams}
|
||||
|
||||
// Trait for generic case class of base trait for copying
|
||||
trait ConcreteBaseTrait[Base] {
|
||||
this: Product =>
|
||||
val _origin: Base
|
||||
|
||||
// Convert back to core-specific tile
|
||||
def convert: Base = {
|
||||
// Reflection Info of this class
|
||||
val fieldNames = (this.getClass.getDeclaredFields map (f => f.getName)).init
|
||||
|
||||
// Reflection of target class
|
||||
val paramClass = _origin.getClass
|
||||
val paramNames = (paramClass.getDeclaredFields map (f => f.getName))
|
||||
val paramCtor = paramClass.getConstructors.head
|
||||
|
||||
// Build a list of parameter in the original parameter class
|
||||
val nameDict = paramNames.zipWithIndex.toMap
|
||||
val indexList = fieldNames map (n => nameDict.get(n))
|
||||
val fieldList = this.productIterator.toList map {
|
||||
case c: ConcreteBaseTrait[_] => c.convert
|
||||
case v => v
|
||||
}
|
||||
val fieldDict = ((indexList zip fieldList) collect { case (Some(i), v) => (i, v) }).toMap
|
||||
val newValues = _origin.asInstanceOf[Product].productIterator.toList.zipWithIndex map
|
||||
{ case (v, i) => (if (fieldDict contains i) fieldDict(i) else v).asInstanceOf[AnyRef] }
|
||||
|
||||
paramCtor.newInstance(newValues:_*).asInstanceOf[Base]
|
||||
}
|
||||
}
|
||||
|
||||
// Case class to change common parameters visible in the base traits. Some fields in the base traits may not be configurable as a
|
||||
// case class constructor parameter for some cores, and those field will be ignored when applied.
|
||||
case class GenericCoreParams(
|
||||
@@ -50,7 +80,7 @@ case class GenericCoreParams(
|
||||
val mtvecWritable: Boolean,
|
||||
// The original object
|
||||
val _origin: CoreParams
|
||||
) extends CoreParams {
|
||||
) extends CoreParams with ConcreteBaseTrait[CoreParams] {
|
||||
def this(coreParams: CoreParams) = this(
|
||||
bootFreqHz = coreParams.bootFreqHz,
|
||||
useVM = coreParams.useVM,
|
||||
@@ -86,27 +116,6 @@ case class GenericCoreParams(
|
||||
_origin = coreParams
|
||||
)
|
||||
|
||||
// Reflection Info of this class
|
||||
val fieldNames = (this.getClass.getDeclaredFields map (f => f.getName)).init
|
||||
|
||||
// Convert back to core-specific tile
|
||||
def convert: CoreParams = {
|
||||
// Reflection of target class
|
||||
val paramClass = _origin.getClass
|
||||
val paramNames = (paramClass.getDeclaredFields map (f => f.getName))
|
||||
val paramCtor = paramClass.getConstructors.head
|
||||
|
||||
// Build a list of parameter in the original parameter class
|
||||
val nameDict = paramNames.zipWithIndex.toMap
|
||||
val indexList = fieldNames map (n => nameDict.get(n))
|
||||
val fieldList = this.productIterator.toList.init
|
||||
val fieldDict = ((indexList zip fieldList) collect { case (Some(i), v) => (i, v) }).toMap
|
||||
val newValues = _origin.asInstanceOf[Product].productIterator.toList.zipWithIndex map
|
||||
{ case (v, i) => (if (fieldDict contains i) fieldDict(i) else v).asInstanceOf[AnyRef] }
|
||||
|
||||
paramCtor.newInstance(newValues:_*).asInstanceOf[CoreParams]
|
||||
}
|
||||
|
||||
// Implement abstract function as placeholder
|
||||
def lrscCycles: Int = _origin.lrscCycles
|
||||
}
|
||||
@@ -121,8 +130,8 @@ case class GenericTileParams(
|
||||
val blockerCtrlAddr: Option[BigInt],
|
||||
val name: Option[String],
|
||||
// The original object
|
||||
val _origin: TileParams
|
||||
) extends TileParams {
|
||||
val _origin: TileParams,
|
||||
) extends TileParams with ConcreteBaseTrait[TileParams] {
|
||||
// Copy constructor to build the params
|
||||
def this(tileParams: TileParams) = this(
|
||||
core = new GenericCoreParams(tileParams.core),
|
||||
@@ -136,44 +145,4 @@ case class GenericTileParams(
|
||||
|
||||
_origin = tileParams
|
||||
)
|
||||
|
||||
// Reflection Info of this class
|
||||
val fieldNames = (this.getClass.getDeclaredFields map (f => f.getName)).init
|
||||
|
||||
// Convert back to core-specific tile
|
||||
def convert: TileParams = {
|
||||
// Reflection of target class
|
||||
val paramClass = _origin.getClass
|
||||
val paramNames = (paramClass.getDeclaredFields map (f => f.getName))
|
||||
val paramCtor = paramClass.getConstructors.head
|
||||
|
||||
// Build a list of parameter in the original parameter class
|
||||
val nameDict = paramNames.zipWithIndex.toMap
|
||||
val indexList = fieldNames map (n => nameDict.get(n))
|
||||
val fieldList = this.productIterator.toList.updated(0, core.convert).init
|
||||
val fieldDict = ((indexList zip fieldList) collect { case (Some(i), v) => (i, v) }).toMap
|
||||
val newValues = _origin.asInstanceOf[Product].productIterator.toList.zipWithIndex map
|
||||
{ case (v, i) => (if (fieldDict contains i) fieldDict(i) else v).asInstanceOf[AnyRef] }
|
||||
|
||||
paramCtor.newInstance(newValues:_*).asInstanceOf[TileParams]
|
||||
}
|
||||
}
|
||||
|
||||
// Extractor to capture TilesKey
|
||||
object TilesKey {
|
||||
def unapply(key: Any): Option[Field[Seq[_]]] =
|
||||
if ((CoreManager.cores filter (core => core.keyEqual(key))).size != 0) Some(key.asInstanceOf[Field[Seq[_]]]) else None
|
||||
}
|
||||
|
||||
class TileSeq(list: Seq[Any]) {
|
||||
def tileMap(f: GenericTileParams => GenericTileParams): Seq[TileParams] = {
|
||||
// If this is not an unpacked tile key, simply throw a type exception
|
||||
// Static type checking is not possible when this class is used with TilesKey extractor
|
||||
val tileList = list.asInstanceOf[Seq[TileParams]]
|
||||
|
||||
tileList map (tileParams => f(new GenericTileParams(tileParams)).convert)
|
||||
}
|
||||
}
|
||||
object TileSeq {
|
||||
implicit def convertSeq(s: Seq[Any]) = new TileSeq(s)
|
||||
}
|
||||
@@ -37,7 +37,7 @@ trait HasChipyardTiles extends HasTiles
|
||||
// Note: the 0-arity function is used to delay the construction of tiles to make sure that they are created
|
||||
// in order
|
||||
val allTilesInfo: Seq[(TileParams, RocketCrossingParams, () => BaseTile)] =
|
||||
(CoreManager.cores flatMap (core => core.instantiateTile(perTileOrGlobalSetting _, logicalTreeNode)))
|
||||
(CoreManager.cores(p) flatMap (core => core.instantiateTile(perTileOrGlobalSetting _, logicalTreeNode)))
|
||||
|
||||
// Make a tile and wire its nodes into the system,
|
||||
// according to the specified type of clock crossing.
|
||||
|
||||
@@ -2,6 +2,7 @@ package chipyard
|
||||
|
||||
import scala.collection.mutable.{LinkedHashSet}
|
||||
|
||||
import freechips.rocketchip.config.{Parameters, Config, Field, View}
|
||||
import freechips.rocketchip.subsystem.{RocketTilesKey}
|
||||
import freechips.rocketchip.tile.{XLen, TileParams}
|
||||
import freechips.rocketchip.config.{Parameters, Field}
|
||||
@@ -102,3 +103,17 @@ class TestSuiteHelper
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Config key of custom test suite.
|
||||
*/
|
||||
case object TestSuitesKey extends Field[(Seq[TileParams], TestSuiteHelper, Parameters) => Unit]((tiles, helper, p) => helper.addGenericTestSuites(tiles)(p))
|
||||
|
||||
/**
|
||||
* Config fragment to add custom test suite factory function.
|
||||
*
|
||||
* @param suiteFactory Test suite factory function. It takes a list of TileParams to be instantiated and the test suite helper.
|
||||
*/
|
||||
class WithTestSuite(suiteFactory: (Seq[TileParams], TestSuiteHelper, Parameters) => Unit) extends Config((site, here, up) => {
|
||||
case TestSuitesKey => suiteFactory
|
||||
})
|
||||
|
||||
@@ -19,6 +19,7 @@ import freechips.rocketchip.util.HasRocketChipStageUtils
|
||||
import freechips.rocketchip.tile.XLen
|
||||
|
||||
import chipyard.{TestSuiteHelper, CoreManager}
|
||||
import chipyard.TestSuitesKey
|
||||
|
||||
class AddDefaultTests extends Phase with PreservesAll[Phase] with HasRocketChipStageUtils {
|
||||
// Make sure we run both after RocketChip's version of this phase, and Rocket Chip's annotation emission phase
|
||||
@@ -33,15 +34,12 @@ class AddDefaultTests extends Phase with PreservesAll[Phase] with HasRocketChipS
|
||||
val suiteHelper = new TestSuiteHelper
|
||||
// Use Xlen as a proxy for detecting if we are a processor-like target
|
||||
// The underlying test suites expect this field to be defined
|
||||
if (p.lift(XLen).nonEmpty) {
|
||||
val customizedSuite: Map[String, TestSuiteHelper => Unit] = Map(
|
||||
// DEFINE CUSTOMIZED TEST HERE, using format ({Core name} -> _.{Test suite builder in TestSuiteHelper})
|
||||
)
|
||||
CoreManager.cores map (core => customizedSuite.get(core.name) match {
|
||||
case Some(builder) => builder(suiteHelper)
|
||||
case None => suiteHelper.addGenericTestSuites(core.tileParamsLookup)
|
||||
})
|
||||
}
|
||||
if (p.lift(XLen).nonEmpty)
|
||||
// If a custom test suite is set up, use the custom test suite
|
||||
if (p.lift(TestSuitesKey).nonEmpty)
|
||||
CoreManager.cores(p) map (core => p(TestSuitesKey).apply(core.tileParamsLookup, suiteHelper, p))
|
||||
else
|
||||
CoreManager.cores(p) map (core => suiteHelper.addGenericTestSuites(core.tileParamsLookup))
|
||||
|
||||
// if hwacha parameter exists then generate its tests
|
||||
// TODO: find a more elegant way to do this. either through
|
||||
|
||||
Reference in New Issue
Block a user