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 sifive.blocks.devices.spi._
|
||||||
|
|
||||||
import chipyard.{BuildTop, BuildSystem}
|
import chipyard.{BuildTop, BuildSystem}
|
||||||
import chipyard.TilesKey
|
import chipyard.{GenericTilesKey, GenericTileConfig}
|
||||||
import chipyard.TileSeq._
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TODO: Why do we need this?
|
* 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))
|
SPIFlashParams(rAddress = 0x10040000, fAddress = 0x20000000, fSize = size))
|
||||||
})
|
})
|
||||||
|
|
||||||
class WithL2TLBs(entries: Int) extends Config((site, here, up) => {
|
class WithL2TLBs(entries: Int) extends GenericTileConfig((site, here, up) => {
|
||||||
case TilesKey(tilesKey) => up(tilesKey) tileMap (tile => tile.copy(
|
case GenericTilesKey(key) => up(GenericTilesKey(key)) map (tile => tile.copy(
|
||||||
core = tile.core.copy(nL2TLBEntries = entries)
|
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 BoomTilesKey => up(BoomTilesKey) map (tile => tile.copy(trace = true))
|
||||||
case ArianeTilesKey => up(ArianeTilesKey) map (tile => tile.copy(trace = true))
|
case ArianeTilesKey => up(ArianeTilesKey) map (tile => tile.copy(trace = true))
|
||||||
case TracePortKey => Some(TracePortParams())
|
case TracePortKey => Some(TracePortParams())
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -15,6 +15,21 @@ import freechips.rocketchip.tile._
|
|||||||
import boom.common.{BoomTile, BoomTilesKey, BoomCrossingKey, BoomTileParams}
|
import boom.common.{BoomTile, BoomTilesKey, BoomCrossingKey, BoomTileParams}
|
||||||
import ariane.{ArianeTile, ArianeTilesKey, ArianeCrossingKey, ArianeTileParams}
|
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
|
// Base trait for all third-party core entries
|
||||||
sealed trait CoreEntryBase {
|
sealed trait CoreEntryBase {
|
||||||
val name: String
|
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
|
// Instantiate a tile and zip it with its parameter info, used by subsystem
|
||||||
def instantiateTile(crossingLookup: (Seq[RocketCrossingParams], Int) => Seq[RocketCrossingParams], logicalTreeNode: LogicalTreeNode)
|
def instantiateTile(crossingLookup: (Seq[RocketCrossingParams], Int) => Seq[RocketCrossingParams], logicalTreeNode: LogicalTreeNode)
|
||||||
(implicit p: Parameters, valName: ValName) = {
|
(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 tileParams = p(tilesKey)
|
||||||
val crossings = crossingLookup(p(crossingKey), tileParams.size)
|
val crossings = crossingLookup(p(crossingKey), tileParams.size)
|
||||||
(tileParams zip crossings) map {
|
(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.
|
// A list of all cores.
|
||||||
object CoreManager {
|
object CoreManager {
|
||||||
val cores: List[CoreEntryBase] = List(
|
// Built-in cores.
|
||||||
// TODO ADD YOUR CORE DEFINITION HERE; note that the
|
val base_cores: List[CoreEntryBase] = List(
|
||||||
new CoreEntry[RocketTileParams, RocketTile]("Rocket", RocketTilesKey, RocketCrossingKey),
|
new CoreEntry[RocketTileParams, RocketTile]("Rocket", RocketTilesKey, RocketCrossingKey),
|
||||||
new CoreEntry[BoomTileParams, BoomTile]("Boom", BoomTilesKey, BoomCrossingKey),
|
new CoreEntry[BoomTileParams, BoomTile]("Boom", BoomTilesKey, BoomCrossingKey),
|
||||||
new CoreEntry[ArianeTileParams, ArianeTile]("Ariane", ArianeTilesKey, ArianeCrossingKey)
|
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 boom.common.{BoomTile, BoomTilesKey, BoomCrossingKey, BoomTileParams}
|
||||||
import ariane.{ArianeTile, ArianeTilesKey, ArianeCrossingKey, ArianeTileParams}
|
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 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 constructor parameter for some cores, and those field will be ignored when applied.
|
||||||
case class GenericCoreParams(
|
case class GenericCoreParams(
|
||||||
@@ -50,7 +80,7 @@ case class GenericCoreParams(
|
|||||||
val mtvecWritable: Boolean,
|
val mtvecWritable: Boolean,
|
||||||
// The original object
|
// The original object
|
||||||
val _origin: CoreParams
|
val _origin: CoreParams
|
||||||
) extends CoreParams {
|
) extends CoreParams with ConcreteBaseTrait[CoreParams] {
|
||||||
def this(coreParams: CoreParams) = this(
|
def this(coreParams: CoreParams) = this(
|
||||||
bootFreqHz = coreParams.bootFreqHz,
|
bootFreqHz = coreParams.bootFreqHz,
|
||||||
useVM = coreParams.useVM,
|
useVM = coreParams.useVM,
|
||||||
@@ -86,27 +116,6 @@ case class GenericCoreParams(
|
|||||||
_origin = coreParams
|
_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
|
// Implement abstract function as placeholder
|
||||||
def lrscCycles: Int = _origin.lrscCycles
|
def lrscCycles: Int = _origin.lrscCycles
|
||||||
}
|
}
|
||||||
@@ -121,8 +130,8 @@ case class GenericTileParams(
|
|||||||
val blockerCtrlAddr: Option[BigInt],
|
val blockerCtrlAddr: Option[BigInt],
|
||||||
val name: Option[String],
|
val name: Option[String],
|
||||||
// The original object
|
// The original object
|
||||||
val _origin: TileParams
|
val _origin: TileParams,
|
||||||
) extends TileParams {
|
) extends TileParams with ConcreteBaseTrait[TileParams] {
|
||||||
// Copy constructor to build the params
|
// Copy constructor to build the params
|
||||||
def this(tileParams: TileParams) = this(
|
def this(tileParams: TileParams) = this(
|
||||||
core = new GenericCoreParams(tileParams.core),
|
core = new GenericCoreParams(tileParams.core),
|
||||||
@@ -136,44 +145,4 @@ case class GenericTileParams(
|
|||||||
|
|
||||||
_origin = tileParams
|
_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
|
// Note: the 0-arity function is used to delay the construction of tiles to make sure that they are created
|
||||||
// in order
|
// in order
|
||||||
val allTilesInfo: Seq[(TileParams, RocketCrossingParams, () => BaseTile)] =
|
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,
|
// Make a tile and wire its nodes into the system,
|
||||||
// according to the specified type of clock crossing.
|
// according to the specified type of clock crossing.
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package chipyard
|
|||||||
|
|
||||||
import scala.collection.mutable.{LinkedHashSet}
|
import scala.collection.mutable.{LinkedHashSet}
|
||||||
|
|
||||||
|
import freechips.rocketchip.config.{Parameters, Config, Field, View}
|
||||||
import freechips.rocketchip.subsystem.{RocketTilesKey}
|
import freechips.rocketchip.subsystem.{RocketTilesKey}
|
||||||
import freechips.rocketchip.tile.{XLen, TileParams}
|
import freechips.rocketchip.tile.{XLen, TileParams}
|
||||||
import freechips.rocketchip.config.{Parameters, Field}
|
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 freechips.rocketchip.tile.XLen
|
||||||
|
|
||||||
import chipyard.{TestSuiteHelper, CoreManager}
|
import chipyard.{TestSuiteHelper, CoreManager}
|
||||||
|
import chipyard.TestSuitesKey
|
||||||
|
|
||||||
class AddDefaultTests extends Phase with PreservesAll[Phase] with HasRocketChipStageUtils {
|
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
|
// 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
|
val suiteHelper = new TestSuiteHelper
|
||||||
// Use Xlen as a proxy for detecting if we are a processor-like target
|
// Use Xlen as a proxy for detecting if we are a processor-like target
|
||||||
// The underlying test suites expect this field to be defined
|
// The underlying test suites expect this field to be defined
|
||||||
if (p.lift(XLen).nonEmpty) {
|
if (p.lift(XLen).nonEmpty)
|
||||||
val customizedSuite: Map[String, TestSuiteHelper => Unit] = Map(
|
// If a custom test suite is set up, use the custom test suite
|
||||||
// DEFINE CUSTOMIZED TEST HERE, using format ({Core name} -> _.{Test suite builder in TestSuiteHelper})
|
if (p.lift(TestSuitesKey).nonEmpty)
|
||||||
)
|
CoreManager.cores(p) map (core => p(TestSuitesKey).apply(core.tileParamsLookup, suiteHelper, p))
|
||||||
CoreManager.cores map (core => customizedSuite.get(core.name) match {
|
else
|
||||||
case Some(builder) => builder(suiteHelper)
|
CoreManager.cores(p) map (core => suiteHelper.addGenericTestSuites(core.tileParamsLookup))
|
||||||
case None => suiteHelper.addGenericTestSuites(core.tileParamsLookup)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// if hwacha parameter exists then generate its tests
|
// if hwacha parameter exists then generate its tests
|
||||||
// TODO: find a more elegant way to do this. either through
|
// TODO: find a more elegant way to do this. either through
|
||||||
|
|||||||
Reference in New Issue
Block a user