From ff583e9e1f5c136d65f510c35584fe2ffff46815 Mon Sep 17 00:00:00 2001 From: Zitao Fang Date: Wed, 20 May 2020 15:44:07 -0700 Subject: [PATCH 01/42] first attempt decoupling --- .../src/main/scala/ConfigFragments.scala | 23 +++++++++--- .../src/main/scala/CoreRegistrar.scala | 37 +++++++++++++++++++ .../chipyard/src/main/scala/Subsystem.scala | 33 ++++++++++------- .../chipyard/src/main/scala/TestSuites.scala | 11 +++--- .../scala/stage/phases/AddDefaultTests.scala | 4 +- 5 files changed, 82 insertions(+), 26 deletions(-) create mode 100644 generators/chipyard/src/main/scala/CoreRegistrar.scala diff --git a/generators/chipyard/src/main/scala/ConfigFragments.scala b/generators/chipyard/src/main/scala/ConfigFragments.scala index 72eaa414..3db4f326 100644 --- a/generators/chipyard/src/main/scala/ConfigFragments.scala +++ b/generators/chipyard/src/main/scala/ConfigFragments.scala @@ -3,7 +3,7 @@ package chipyard.config import chisel3._ import chisel3.util.{log2Up} -import freechips.rocketchip.config.{Field, Parameters, Config} +import freechips.rocketchip.config.{Field, Parameters, Config, View} import freechips.rocketchip.subsystem.{SystemBusKey, RocketTilesKey, WithRoccExample, WithNMemoryChannels, WithNBigCores, WithRV32, CacheBlockBytes} import freechips.rocketchip.diplomacy.{LazyModule, ValName} import freechips.rocketchip.devices.tilelink.BootROMParams @@ -13,7 +13,6 @@ import freechips.rocketchip.rocket.{RocketCoreParams, MulDivParams, DCacheParams import freechips.rocketchip.util.{AsyncResetReg} import boom.common.{BoomTilesKey} -import ariane.{ArianeTilesKey} import testchipip._ import hwacha.{Hwacha} @@ -23,6 +22,7 @@ import sifive.blocks.devices.uart._ import sifive.blocks.devices.spi._ import chipyard.{BuildTop, BuildSystem} +import chipyard.{CoreRegistrar, CoreRegisterEntryBase} /** * TODO: Why do we need this? @@ -147,8 +147,21 @@ class WithControlCore extends Config((site, here, up) => { case MaxHartIdBits => log2Up(up(RocketTilesKey, site).size + up(BoomTilesKey, site).size + 1) }) +trait TraceIOMatch { + this: CoreRegisterEntryBase => + val matchTile: (View, View, View) => PartialFunction[Field[Seq[TileParams]],Any] = ((site, here, up) => { + // TODO: XXX What's the "tile" here? + case tilesKey => up(tilesKey) map (tile => tile.copy(trace = true)) + }) +} + 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()) + val coreMatch = (coreList: List[CoreRegisterEntryBase]) => coreList match { + case coreEntry :: tail => coreEntry.matchTile(site, here, up) orElse coreMatch(tail) + case Nil => { + case BoomTilesKey => up(BoomTilesKey) map (tile => tile.copy(trace = true)) + case TracePortKey => Some(TracePortParams()) + } + } + coreMatch(CoreRegistrar.cores) }) diff --git a/generators/chipyard/src/main/scala/CoreRegistrar.scala b/generators/chipyard/src/main/scala/CoreRegistrar.scala new file mode 100644 index 00000000..a0b1625c --- /dev/null +++ b/generators/chipyard/src/main/scala/CoreRegistrar.scala @@ -0,0 +1,37 @@ +package chipyard + +import chisel3._ + +import freechips.rocketchip.config.{Parameters, Config, Field} +import freechips.rocketchip.subsystem.{SystemBusKey, RocketTilesKey, RocketCrossingParams} +import freechips.rocketchip.devices.tilelink.{BootROMParams} +import freechips.rocketchip.diplomacy.{SynchronousCrossing, AsynchronousCrossing, RationalCrossing} +import freechips.rocketchip.rocket._ +import freechips.rocketchip.tile._ + +import ariane.{ArianeTile, ArianeTilesKey, ArianeCrossingKey, ArianeTileParams} + +import chipyard.config.TraceIOMatch + +// Third-party core entries +sealed trait CoreRegisterEntryBase { + type Tile + type TitleParams + def tilesKey: Field[Seq[TitleParams]] + def crossingKey: Field[Seq[RocketCrossingParams]] +} + +class CoreRegisterEntry[TileT <: BaseTile, TileParamsT <: CoreParams](tk: Field[Seq[TileParamsT]], ck: Field[Seq[RocketCrossingParams]]) + extends CoreRegisterEntryBase with TraceIOMatch { + type Tile = TileT + type TileParams = TileParamsT + def tilesKey = tk + def crossingKey = ck +} + +object CoreRegistrar { + val cores: List[CoreRegisterEntryBase] = List( + // ADD YOUR CORE DEFINITION HERE + new CoreRegisterEntry[ArianeTile, ArianeTileParams](ArianeTilesKey, ArianeCrossingKey) + ) +} \ No newline at end of file diff --git a/generators/chipyard/src/main/scala/Subsystem.scala b/generators/chipyard/src/main/scala/Subsystem.scala index 99c31472..fcb58fc4 100644 --- a/generators/chipyard/src/main/scala/Subsystem.scala +++ b/generators/chipyard/src/main/scala/Subsystem.scala @@ -22,7 +22,6 @@ import freechips.rocketchip.subsystem._ import freechips.rocketchip.amba.axi4._ import boom.common.{BoomTile, BoomTilesKey, BoomCrossingKey, BoomTileParams} -import ariane.{ArianeTile, ArianeTilesKey, ArianeCrossingKey, ArianeTileParams} import testchipip.{DromajoHelper} @@ -36,14 +35,17 @@ trait HasChipyardTiles extends HasTiles protected val rocketTileParams = p(RocketTilesKey) protected val boomTileParams = p(BoomTilesKey) - protected val arianeTileParams = p(ArianeTilesKey) + protected val coreTileParams = CoreRegistrar.cores map (coreType => p(coreType.tilesKey)) // crossing can either be per tile or global (aka only 1 crossing specified) private val rocketCrossings = perTileOrGlobalSetting(p(RocketCrossingKey), rocketTileParams.size) private val boomCrossings = perTileOrGlobalSetting(p(BoomCrossingKey), boomTileParams.size) - private val arianeCrossings = perTileOrGlobalSetting(p(ArianeCrossingKey), arianeTileParams.size) + private val coreCrossings = (CoreRegistrar.cores zip coreTileParams) map ((coreType, tileParams) => + perTileOrGlobalSetting(p(coreType.crossingKey), tileParams.size)) - val allTilesInfo = (rocketTileParams ++ boomTileParams ++ arianeTileParams) zip (rocketCrossings ++ boomCrossings ++ arianeCrossings) + // TODO: XXX The "tiles" below scan for hartId but it is not in CoreParams. Should that be added in later + // revision, or I have to use reflection to get that parameter? + val allTilesInfo = (rocketTileParams ++ boomTileParams ++ coreTileParams) zip (rocketCrossings ++ boomCrossings ++ coreCrossings) // Make a tile and wire its nodes into the system, // according to the specified type of clock crossing. @@ -55,17 +57,22 @@ trait HasChipyardTiles extends HasTiles val tiles = allTilesInfo.sortWith(_._1.hartId < _._1.hartId).map { case (param, crossing) => { - val tile = param match { - case r: RocketTileParams => { - LazyModule(new RocketTile(r, crossing, PriorityMuxHartIdFromSeq(rocketTileParams), logicalTreeNode)) - } - case b: BoomTileParams => { - LazyModule(new BoomTile(b, crossing, PriorityMuxHartIdFromSeq(boomTileParams), logicalTreeNode)) - } - case a: ArianeTileParams => { - LazyModule(new ArianeTile(a, crossing, PriorityMuxHartIdFromSeq(arianeTileParams), logicalTreeNode)) + val tileMatch = coreAndtileParamsList => { + case (coreType, tileParams) :: tail => (param => { + case a: coreType.TileParams => { + LazyModule(new coreType.Tile(a, crossing, PriorityMuxHartIdFromSeq(tileParams), logicalTreeNode)) + } + }) orElse tileMatch(tail) + case Nil => param => { + case r: RocketTileParams => { + LazyModule(new RocketTile(r, crossing, PriorityMuxHartIdFromSeq(rocketTileParams), logicalTreeNode)) + } + case b: BoomTileParams => { + LazyModule(new BoomTile(b, crossing, PriorityMuxHartIdFromSeq(boomTileParams), logicalTreeNode)) + } } } + val tile = tileMatch(CoreRegistrar.cores zip coreTileParams) connectMasterPortsToSBus(tile, crossing) connectSlavePortsToCBus(tile, crossing) connectInterrupts(tile, debugOpt, clintOpt, plicOpt) diff --git a/generators/chipyard/src/main/scala/TestSuites.scala b/generators/chipyard/src/main/scala/TestSuites.scala index 9fdef05a..f90e3d23 100644 --- a/generators/chipyard/src/main/scala/TestSuites.scala +++ b/generators/chipyard/src/main/scala/TestSuites.scala @@ -3,12 +3,11 @@ package chipyard import scala.collection.mutable.{LinkedHashSet} import freechips.rocketchip.subsystem.{RocketTilesKey} -import freechips.rocketchip.tile.{XLen} -import freechips.rocketchip.config.{Parameters} +import freechips.rocketchip.tile.{XLen, CoreParams} +import freechips.rocketchip.config.{Parameters, Field} import freechips.rocketchip.system.{TestGeneration, RegressionTestSuite, RocketTestSuite} import boom.common.{BoomTilesKey} -import ariane.{ArianeTilesKey} /** * A set of pre-chosen regression tests @@ -144,11 +143,11 @@ class TestSuiteHelper } /** - * Add Ariane tests (asm, bmark, regression) + * Add third-party core (including Ariane) tests (asm, bmark, regression) */ - def addArianeTestSuites(implicit p: Parameters) = { + def addThirdPartyTestSuites[TileParams <: CoreParams](tilesKey: Field[Seq[TileParams]])(implicit p: Parameters) = { val xlen = p(XLen) - p(ArianeTilesKey).find(_.hartId == 0).map { tileParams => + p(tilesKey).find(_.hartId == 0).map { tileParams => val coreParams = tileParams.core val vm = coreParams.useVM val env = if (vm) List("p","v") else List("p") diff --git a/generators/chipyard/src/main/scala/stage/phases/AddDefaultTests.scala b/generators/chipyard/src/main/scala/stage/phases/AddDefaultTests.scala index fce5d432..3d367ffa 100644 --- a/generators/chipyard/src/main/scala/stage/phases/AddDefaultTests.scala +++ b/generators/chipyard/src/main/scala/stage/phases/AddDefaultTests.scala @@ -17,7 +17,7 @@ import freechips.rocketchip.stage.phases.{RocketTestSuiteAnnotation} import freechips.rocketchip.system.{RocketTestSuite, TestGeneration} import freechips.rocketchip.util.HasRocketChipStageUtils -import chipyard.TestSuiteHelper +import chipyard.{TestSuiteHelper, CoreRegistrar} 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 @@ -32,7 +32,7 @@ class AddDefaultTests extends Phase with PreservesAll[Phase] with HasRocketChipS val suiteHelper = new TestSuiteHelper suiteHelper.addRocketTestSuites suiteHelper.addBoomTestSuites - suiteHelper.addArianeTestSuites + CoreRegistrar.cores map suiteHelper.addThirdPartyTestSuites(_.tilesKey) // if hwacha parameter exists then generate its tests // TODO: find a more elegant way to do this. either through From adb85c98caed9190abae7a927ee68fb61e5b4a33 Mon Sep 17 00:00:00 2001 From: Zitao Fang Date: Thu, 21 May 2020 12:35:26 -0700 Subject: [PATCH 02/42] Some Revisions --- .../src/main/scala/ConfigFragments.scala | 21 +++++-------- .../src/main/scala/CoreRegistrar.scala | 31 ++++++++++++------- .../chipyard/src/main/scala/Subsystem.scala | 30 ++++++++---------- 3 files changed, 39 insertions(+), 43 deletions(-) diff --git a/generators/chipyard/src/main/scala/ConfigFragments.scala b/generators/chipyard/src/main/scala/ConfigFragments.scala index 3db4f326..6eca517f 100644 --- a/generators/chipyard/src/main/scala/ConfigFragments.scala +++ b/generators/chipyard/src/main/scala/ConfigFragments.scala @@ -147,21 +147,14 @@ class WithControlCore extends Config((site, here, up) => { case MaxHartIdBits => log2Up(up(RocketTilesKey, site).size + up(BoomTilesKey, site).size + 1) }) -trait TraceIOMatch { - this: CoreRegisterEntryBase => - val matchTile: (View, View, View) => PartialFunction[Field[Seq[TileParams]],Any] = ((site, here, up) => { - // TODO: XXX What's the "tile" here? - case tilesKey => up(tilesKey) map (tile => tile.copy(trace = true)) - }) -} - class WithTraceIO extends Config((site, here, up) => { - val coreMatch = (coreList: List[CoreRegisterEntryBase]) => coreList match { - case coreEntry :: tail => coreEntry.matchTile(site, here, up) orElse coreMatch(tail) - case Nil => { - case BoomTilesKey => up(BoomTilesKey) map (tile => tile.copy(trace = true)) - case TracePortKey => Some(TracePortParams()) + val coreMatch: List[CoreRegisterEntryBase] => PartialFunction[Any,Any] = + coreList => coreList match { + case coreEntry :: tail => coreEntry.enableTileTrace(site, here, up) orElse coreMatch(tail) + case Nil => { + case BoomTilesKey => up(BoomTilesKey) map (tile => tile.copy(trace = true)) + case TracePortKey => Some(TracePortParams()) + } } - } coreMatch(CoreRegistrar.cores) }) diff --git a/generators/chipyard/src/main/scala/CoreRegistrar.scala b/generators/chipyard/src/main/scala/CoreRegistrar.scala index a0b1625c..b1503361 100644 --- a/generators/chipyard/src/main/scala/CoreRegistrar.scala +++ b/generators/chipyard/src/main/scala/CoreRegistrar.scala @@ -2,36 +2,43 @@ package chipyard import chisel3._ -import freechips.rocketchip.config.{Parameters, Config, Field} +import freechips.rocketchip.config.{Parameters, Config, Field, View} import freechips.rocketchip.subsystem.{SystemBusKey, RocketTilesKey, RocketCrossingParams} -import freechips.rocketchip.devices.tilelink.{BootROMParams} -import freechips.rocketchip.diplomacy.{SynchronousCrossing, AsynchronousCrossing, RationalCrossing} +import freechips.rocketchip.diplomacy.LazyModule +import freechips.rocketchip.diplomaticobjectmodel.logicaltree.LogicalTreeNode import freechips.rocketchip.rocket._ import freechips.rocketchip.tile._ import ariane.{ArianeTile, ArianeTilesKey, ArianeCrossingKey, ArianeTileParams} -import chipyard.config.TraceIOMatch - // Third-party core entries sealed trait CoreRegisterEntryBase { - type Tile - type TitleParams - def tilesKey: Field[Seq[TitleParams]] + type TileParams <: CoreParams + def tilesKey: Field[Seq[TileParams]] def crossingKey: Field[Seq[RocketCrossingParams]] + def enableTileTrace(site: View, here: View, up: View): PartialFunction[Any, Any] + def instantiateTile(param: TileParams, crossing: RocketCrossingParams, + logicalTreeNode: LogicalTreeNode, p: Parameters): Option[BaseTile] } -class CoreRegisterEntry[TileT <: BaseTile, TileParamsT <: CoreParams](tk: Field[Seq[TileParamsT]], ck: Field[Seq[RocketCrossingParams]]) - extends CoreRegisterEntryBase with TraceIOMatch { - type Tile = TileT +class CoreRegisterEntry[TileParamsT <: CoreParams, TileT <: BaseTile](tk: Field[Seq[TileParamsT]], ck: Field[Seq[RocketCrossingParams]], + tileInstantiator: (TileParamsT, RocketCrossingParams, LookupByHartIdImpl, LogicalTreeNode, Parameters) => TileT) extends CoreRegisterEntryBase { type TileParams = TileParamsT def tilesKey = tk def crossingKey = ck + def enableTileTrace(site: View, here: View, up: View): PartialFunction[Any, Any] = { + case in if in == tilesKey => up(this.tilesKey) map (tile => tile.copy(trace = true)) + } + def instantiateTile(param: TileParams, crossing: RocketCrossingParams, + logicalTreeNode: LogicalTreeNode, p: Parameters): Option[BaseTile] = param match { + case a: TileParams => Some(tileInstantiator(a, crossing, PriorityMuxHartIdFromSeq(p(tilesKey)), logicalTreeNode, p)) + case _ => None + } } object CoreRegistrar { val cores: List[CoreRegisterEntryBase] = List( // ADD YOUR CORE DEFINITION HERE - new CoreRegisterEntry[ArianeTile, ArianeTileParams](ArianeTilesKey, ArianeCrossingKey) + new CoreRegisterEntry[ArianeTileParams, ArianeTile](ArianeTilesKey, ArianeCrossingKey, ((a, b, c, d, p) => {new ArianeTile(a, b, c, d)})) ) } \ No newline at end of file diff --git a/generators/chipyard/src/main/scala/Subsystem.scala b/generators/chipyard/src/main/scala/Subsystem.scala index fcb58fc4..7b554d2a 100644 --- a/generators/chipyard/src/main/scala/Subsystem.scala +++ b/generators/chipyard/src/main/scala/Subsystem.scala @@ -40,12 +40,13 @@ trait HasChipyardTiles extends HasTiles // crossing can either be per tile or global (aka only 1 crossing specified) private val rocketCrossings = perTileOrGlobalSetting(p(RocketCrossingKey), rocketTileParams.size) private val boomCrossings = perTileOrGlobalSetting(p(BoomCrossingKey), boomTileParams.size) - private val coreCrossings = (CoreRegistrar.cores zip coreTileParams) map ((coreType, tileParams) => - perTileOrGlobalSetting(p(coreType.crossingKey), tileParams.size)) + private val coreCrossings = (CoreRegistrar.cores zip coreTileParams) map (_ match { + case (coreType, tileParams) => perTileOrGlobalSetting(p(coreType.crossingKey), tileParams.size) + }) // TODO: XXX The "tiles" below scan for hartId but it is not in CoreParams. Should that be added in later // revision, or I have to use reflection to get that parameter? - val allTilesInfo = (rocketTileParams ++ boomTileParams ++ coreTileParams) zip (rocketCrossings ++ boomCrossings ++ coreCrossings) + val allTilesInfo = (rocketTileParams ++ boomTileParams ++ coreTileParams.flatten) zip (rocketCrossings ++ boomCrossings ++ coreCrossings.flatten) // Make a tile and wire its nodes into the system, // according to the specified type of clock crossing. @@ -57,22 +58,17 @@ trait HasChipyardTiles extends HasTiles val tiles = allTilesInfo.sortWith(_._1.hartId < _._1.hartId).map { case (param, crossing) => { - val tileMatch = coreAndtileParamsList => { - case (coreType, tileParams) :: tail => (param => { - case a: coreType.TileParams => { - LazyModule(new coreType.Tile(a, crossing, PriorityMuxHartIdFromSeq(tileParams), logicalTreeNode)) - } - }) orElse tileMatch(tail) - case Nil => param => { - case r: RocketTileParams => { - LazyModule(new RocketTile(r, crossing, PriorityMuxHartIdFromSeq(rocketTileParams), logicalTreeNode)) - } - case b: BoomTileParams => { - LazyModule(new BoomTile(b, crossing, PriorityMuxHartIdFromSeq(boomTileParams), logicalTreeNode)) - } + val tile = param match { + case r: RocketTileParams => { + LazyModule(new RocketTile(r, crossing, PriorityMuxHartIdFromSeq(rocketTileParams), logicalTreeNode)) } + case b: BoomTileParams => { + LazyModule(new BoomTile(b, crossing, PriorityMuxHartIdFromSeq(boomTileParams), logicalTreeNode)) + } + case _ => LazyModule( + (CoreRegistrar.cores collect (core => core.instantiateTile(param, crossing, paramList, logicalTreeNode, p)).unlift()) (0) + ) } - val tile = tileMatch(CoreRegistrar.cores zip coreTileParams) connectMasterPortsToSBus(tile, crossing) connectSlavePortsToCBus(tile, crossing) connectInterrupts(tile, debugOpt, clintOpt, plicOpt) From 15c1f5adba5d6c56748573beaa32432a437338d4 Mon Sep 17 00:00:00 2001 From: Zitao Fang Date: Mon, 25 May 2020 10:47:58 -0700 Subject: [PATCH 03/42] Sync works to my laptop --- .../src/main/scala/ConfigFragments.scala | 7 +++++ .../src/main/scala/CoreRegistrar.scala | 30 +++++++++++++++++-- 2 files changed, 34 insertions(+), 3 deletions(-) diff --git a/generators/chipyard/src/main/scala/ConfigFragments.scala b/generators/chipyard/src/main/scala/ConfigFragments.scala index 6eca517f..cdf84327 100644 --- a/generators/chipyard/src/main/scala/ConfigFragments.scala +++ b/generators/chipyard/src/main/scala/ConfigFragments.scala @@ -23,6 +23,7 @@ import sifive.blocks.devices.spi._ import chipyard.{BuildTop, BuildSystem} import chipyard.{CoreRegistrar, CoreRegisterEntryBase} +import chipyard.hlist /** * TODO: Why do we need this? @@ -147,6 +148,12 @@ class WithControlCore extends Config((site, here, up) => { case MaxHartIdBits => log2Up(up(RocketTilesKey, site).size + up(BoomTilesKey, site).size + 1) }) +class WithTraceIOHMap extends ConfigHMap { + override def apply[I](v: I) = (site, here, up) => { + + } +} + class WithTraceIO extends Config((site, here, up) => { val coreMatch: List[CoreRegisterEntryBase] => PartialFunction[Any,Any] = coreList => coreList match { diff --git a/generators/chipyard/src/main/scala/CoreRegistrar.scala b/generators/chipyard/src/main/scala/CoreRegistrar.scala index b1503361..766172d1 100644 --- a/generators/chipyard/src/main/scala/CoreRegistrar.scala +++ b/generators/chipyard/src/main/scala/CoreRegistrar.scala @@ -1,5 +1,8 @@ package chipyard +import scala.reflect.ClassTag +import scala.reflect.runtime.universe._ + import chisel3._ import freechips.rocketchip.config.{Parameters, Config, Field, View} @@ -16,16 +19,27 @@ sealed trait CoreRegisterEntryBase { type TileParams <: CoreParams def tilesKey: Field[Seq[TileParams]] def crossingKey: Field[Seq[RocketCrossingParams]] + + def findTilesWithFilter(view: View, p: Any => View): PartialFunction[Any, Seq[AnyRef]] + def enableTileTrace(site: View, here: View, up: View): PartialFunction[Any, Any] def instantiateTile(param: TileParams, crossing: RocketCrossingParams, logicalTreeNode: LogicalTreeNode, p: Parameters): Option[BaseTile] } -class CoreRegisterEntry[TileParamsT <: CoreParams, TileT <: BaseTile](tk: Field[Seq[TileParamsT]], ck: Field[Seq[RocketCrossingParams]], - tileInstantiator: (TileParamsT, RocketCrossingParams, LookupByHartIdImpl, LogicalTreeNode, Parameters) => TileT) extends CoreRegisterEntryBase { +class CoreRegisterEntry[TileParamsT <: CoreParams, TileT <: BaseTile]( + tk: Field[Seq[TileParamsT]], + ck: Field[Seq[RocketCrossingParams]], + tileInstantiator: (TileParamsT, RocketCrossingParams, LookupByHartIdImpl, LogicalTreeNode, Parameters) => TileT +) extends CoreRegisterEntryBase { type TileParams = TileParamsT def tilesKey = tk def crossingKey = ck + + def findTilesWithFilter(view: View, p: Any => View) = { + case key if (key == tk && p(tk)) => view(tk) + } + def enableTileTrace(site: View, here: View, up: View): PartialFunction[Any, Any] = { case in if in == tilesKey => up(this.tilesKey) map (tile => tile.copy(trace = true)) } @@ -41,4 +55,14 @@ object CoreRegistrar { // ADD YOUR CORE DEFINITION HERE new CoreRegisterEntry[ArianeTileParams, ArianeTile](ArianeTilesKey, ArianeCrossingKey, ((a, b, c, d, p) => {new ArianeTile(a, b, c, d)})) ) -} \ No newline at end of file +} + +// Core Generic Config - change properties in the given map +class GenericConfig(properties: Map[String, Any], filterFunc: Any => Bool = (_ => true)) { + val configFunc: (View, View, View) => PartialFunction[Any, Any] = ((site, here, up) => key => { + val tiles = CoreRegistrar.cores flatMap _.findTilesWithFilter(up, filterFunc).lift(key) + if (tiles.size == 0) None else Some(tiles map (tile => { + val method = ClassTag(tile.getClass).member(TermName(methodName)).asMethod + })).unlift + }).unlift +} From c0bafa306c694764d3593bab8d4717023c434821 Mon Sep 17 00:00:00 2001 From: Zitao Fang Date: Mon, 25 May 2020 13:22:28 -0700 Subject: [PATCH 04/42] Config Done --- .../src/main/scala/ConfigFragments.scala | 22 ++---- .../chipyard/src/main/scala/CoreManager.scala | 76 +++++++++++++++++++ .../src/main/scala/CoreRegistrar.scala | 68 ----------------- .../chipyard/src/main/scala/TestSuites.scala | 2 +- 4 files changed, 82 insertions(+), 86 deletions(-) create mode 100644 generators/chipyard/src/main/scala/CoreManager.scala delete mode 100644 generators/chipyard/src/main/scala/CoreRegistrar.scala diff --git a/generators/chipyard/src/main/scala/ConfigFragments.scala b/generators/chipyard/src/main/scala/ConfigFragments.scala index cdf84327..e87b833a 100644 --- a/generators/chipyard/src/main/scala/ConfigFragments.scala +++ b/generators/chipyard/src/main/scala/ConfigFragments.scala @@ -148,20 +148,8 @@ class WithControlCore extends Config((site, here, up) => { case MaxHartIdBits => log2Up(up(RocketTilesKey, site).size + up(BoomTilesKey, site).size + 1) }) -class WithTraceIOHMap extends ConfigHMap { - override def apply[I](v: I) = (site, here, up) => { - - } -} - -class WithTraceIO extends Config((site, here, up) => { - val coreMatch: List[CoreRegisterEntryBase] => PartialFunction[Any,Any] = - coreList => coreList match { - case coreEntry :: tail => coreEntry.enableTileTrace(site, here, up) orElse coreMatch(tail) - case Nil => { - case BoomTilesKey => up(BoomTilesKey) map (tile => tile.copy(trace = true)) - case TracePortKey => Some(TracePortParams()) - } - } - coreMatch(CoreRegistrar.cores) -}) +class WithTraceIO extends Config((site, here, up) => + GenericConfig(Map("trace" -> true)) (site, here, up) orElse { + case BoomTilesKey => up(BoomTilesKey) map (tile => tile.copy(trace = true)) + case TracePortKey => Some(TracePortParams()) + }) diff --git a/generators/chipyard/src/main/scala/CoreManager.scala b/generators/chipyard/src/main/scala/CoreManager.scala new file mode 100644 index 00000000..72c5dc85 --- /dev/null +++ b/generators/chipyard/src/main/scala/CoreManager.scala @@ -0,0 +1,76 @@ +package chipyard + +import scala.reflect.ClassTag +import scala.reflect.runtime.universe._ + +import chisel3._ + +import freechips.rocketchip.config.{Parameters, Config, Field, View} +import freechips.rocketchip.subsystem.{SystemBusKey, RocketTilesKey, RocketCrossingParams} +import freechips.rocketchip.diplomacy.LazyModule +import freechips.rocketchip.diplomaticobjectmodel.logicaltree.LogicalTreeNode +import freechips.rocketchip.rocket._ +import freechips.rocketchip.tile._ + +import ariane.{ArianeTile, ArianeTilesKey, ArianeCrossingKey, ArianeTileParams} + +// Third-party core entries +sealed trait CoreEntryBase { + def updateWithFilter(view: View, p: Any => View): (Map[String, Any] => PartialFunction[Any, Seq[AnyRef]]) + + def instantiateTile(param: TileParams, crossing: RocketCrossingParams, + logicalTreeNode: LogicalTreeNode, p: Parameters): Option[BaseTile] +} + +class CoreEntry[TileParamsT <: CoreParams, TileT <: BaseTile]( + tk: Field[Seq[TileParamsT]], + ck: Field[Seq[RocketCrossingParams]] +) extends CoreEntryBase { + private val mirror = runtimeMirror(getClass.getClassLoader) + private val paramClass = mirror.runtimeClass(typeOf[TileParamsT].typeSymbol.asClass) + private val paramNames = Map((paramClass.getDeclaredFields map _.getName).zipWithIndex) + private val paramCtr = paramClass.getConstructors.head + + private val tileClass = mirror.runtimeClass(typeOf[TileT].typeSymbol.asClass) + private val tileCtr = paramClass.getConstructors.head + + // copy() function in + def copyTileParam(tileParam: AnyRef, properties: Map[String, Any]) = { + val values = foo.productIterator.toList + val indexedProperties = properties map (key => (paramNames(key), properties(key))) + val newValues = (0 until values.size) map + (i => if (indexedProperties contains i) indexedProperties(i) else values(i)) + paramCtr.newInstance(newValues:_*) + } + + def updateWithFilter(view: View, p: Any => View) = { + case key if (key == tk && p(tk)) => view(tk) map + (tile => properties => copyTileParam(tile, properties)) + } + + def instantiateTile(param: TileParams, crossing: RocketCrossingParams, + logicalTreeNode: LogicalTreeNode, p: Parameters): Option[BaseTile] = param match { + case a: TileParams => Some(tileCtr.newInstance(a, crossing, PriorityMuxHartIdFromSeq(p(tilesKey)), logicalTreeNode, p)) + case _ => None + } +} + +object CoreManager { + val cores: List[CoreEntryBase] = List( + // ADD YOUR CORE DEFINITION HERE + new CoreEntry[ArianeTileParams, ArianeTile](ArianeTilesKey, ArianeCrossingKey) + ) +} + +// Core Generic Config - change properties in the given map +class GenericConfig(properties: Map[String, Any], filterFunc: Any => Bool) { + val configFunc: (View, View, View) => PartialFunction[Any, Any] = ((site, here, up) => key => { + val tiles = CoreManager.cores flatMap _.updateWithFilter(up, filterFunc).lift(key) + if (tiles.size == 0) None else Some(tiles map _(properties)) + }).unlift +} + +object GenericConfig { + def apply(properties: Map[String, Any], filterFunc: Any => Bool = (_ => true)) = + new GenericConfig(properties, filterFunc).configFunc +} diff --git a/generators/chipyard/src/main/scala/CoreRegistrar.scala b/generators/chipyard/src/main/scala/CoreRegistrar.scala deleted file mode 100644 index 766172d1..00000000 --- a/generators/chipyard/src/main/scala/CoreRegistrar.scala +++ /dev/null @@ -1,68 +0,0 @@ -package chipyard - -import scala.reflect.ClassTag -import scala.reflect.runtime.universe._ - -import chisel3._ - -import freechips.rocketchip.config.{Parameters, Config, Field, View} -import freechips.rocketchip.subsystem.{SystemBusKey, RocketTilesKey, RocketCrossingParams} -import freechips.rocketchip.diplomacy.LazyModule -import freechips.rocketchip.diplomaticobjectmodel.logicaltree.LogicalTreeNode -import freechips.rocketchip.rocket._ -import freechips.rocketchip.tile._ - -import ariane.{ArianeTile, ArianeTilesKey, ArianeCrossingKey, ArianeTileParams} - -// Third-party core entries -sealed trait CoreRegisterEntryBase { - type TileParams <: CoreParams - def tilesKey: Field[Seq[TileParams]] - def crossingKey: Field[Seq[RocketCrossingParams]] - - def findTilesWithFilter(view: View, p: Any => View): PartialFunction[Any, Seq[AnyRef]] - - def enableTileTrace(site: View, here: View, up: View): PartialFunction[Any, Any] - def instantiateTile(param: TileParams, crossing: RocketCrossingParams, - logicalTreeNode: LogicalTreeNode, p: Parameters): Option[BaseTile] -} - -class CoreRegisterEntry[TileParamsT <: CoreParams, TileT <: BaseTile]( - tk: Field[Seq[TileParamsT]], - ck: Field[Seq[RocketCrossingParams]], - tileInstantiator: (TileParamsT, RocketCrossingParams, LookupByHartIdImpl, LogicalTreeNode, Parameters) => TileT -) extends CoreRegisterEntryBase { - type TileParams = TileParamsT - def tilesKey = tk - def crossingKey = ck - - def findTilesWithFilter(view: View, p: Any => View) = { - case key if (key == tk && p(tk)) => view(tk) - } - - def enableTileTrace(site: View, here: View, up: View): PartialFunction[Any, Any] = { - case in if in == tilesKey => up(this.tilesKey) map (tile => tile.copy(trace = true)) - } - def instantiateTile(param: TileParams, crossing: RocketCrossingParams, - logicalTreeNode: LogicalTreeNode, p: Parameters): Option[BaseTile] = param match { - case a: TileParams => Some(tileInstantiator(a, crossing, PriorityMuxHartIdFromSeq(p(tilesKey)), logicalTreeNode, p)) - case _ => None - } -} - -object CoreRegistrar { - val cores: List[CoreRegisterEntryBase] = List( - // ADD YOUR CORE DEFINITION HERE - new CoreRegisterEntry[ArianeTileParams, ArianeTile](ArianeTilesKey, ArianeCrossingKey, ((a, b, c, d, p) => {new ArianeTile(a, b, c, d)})) - ) -} - -// Core Generic Config - change properties in the given map -class GenericConfig(properties: Map[String, Any], filterFunc: Any => Bool = (_ => true)) { - val configFunc: (View, View, View) => PartialFunction[Any, Any] = ((site, here, up) => key => { - val tiles = CoreRegistrar.cores flatMap _.findTilesWithFilter(up, filterFunc).lift(key) - if (tiles.size == 0) None else Some(tiles map (tile => { - val method = ClassTag(tile.getClass).member(TermName(methodName)).asMethod - })).unlift - }).unlift -} diff --git a/generators/chipyard/src/main/scala/TestSuites.scala b/generators/chipyard/src/main/scala/TestSuites.scala index f90e3d23..a4944355 100644 --- a/generators/chipyard/src/main/scala/TestSuites.scala +++ b/generators/chipyard/src/main/scala/TestSuites.scala @@ -147,7 +147,7 @@ class TestSuiteHelper */ def addThirdPartyTestSuites[TileParams <: CoreParams](tilesKey: Field[Seq[TileParams]])(implicit p: Parameters) = { val xlen = p(XLen) - p(tilesKey).find(_.hartId == 0).map { tileParams => + p(tilesKey).asInstanceOf[Seq[CoreParams]].find(_.hartId == 0).map { tileParams => val coreParams = tileParams.core val vm = coreParams.useVM val env = if (vm) List("p","v") else List("p") From 2edfcb9022f9904e99820477423c9ba57ec4463c Mon Sep 17 00:00:00 2001 From: Zitao Fang Date: Mon, 25 May 2020 13:58:04 -0700 Subject: [PATCH 05/42] Subsystem done --- .../chipyard/src/main/scala/CoreManager.scala | 32 +++++++++-------- .../chipyard/src/main/scala/Subsystem.scala | 34 ++++++++----------- 2 files changed, 32 insertions(+), 34 deletions(-) diff --git a/generators/chipyard/src/main/scala/CoreManager.scala b/generators/chipyard/src/main/scala/CoreManager.scala index 72c5dc85..39c3a678 100644 --- a/generators/chipyard/src/main/scala/CoreManager.scala +++ b/generators/chipyard/src/main/scala/CoreManager.scala @@ -17,9 +17,8 @@ import ariane.{ArianeTile, ArianeTilesKey, ArianeCrossingKey, ArianeTileParams} // Third-party core entries sealed trait CoreEntryBase { def updateWithFilter(view: View, p: Any => View): (Map[String, Any] => PartialFunction[Any, Seq[AnyRef]]) - - def instantiateTile(param: TileParams, crossing: RocketCrossingParams, - logicalTreeNode: LogicalTreeNode, p: Parameters): Option[BaseTile] + def instantiateTile(crossingLookup: (Seq[RocketCrossingParams], Int) => ClockCrossingType) + (implicit logicalTreeNode: LogicalTreeNode, p: Parameters): (CoreParams, ClockCrossingType, BaseTile) } class CoreEntry[TileParamsT <: CoreParams, TileT <: BaseTile]( @@ -48,20 +47,18 @@ class CoreEntry[TileParamsT <: CoreParams, TileT <: BaseTile]( (tile => properties => copyTileParam(tile, properties)) } - def instantiateTile(param: TileParams, crossing: RocketCrossingParams, - logicalTreeNode: LogicalTreeNode, p: Parameters): Option[BaseTile] = param match { - case a: TileParams => Some(tileCtr.newInstance(a, crossing, PriorityMuxHartIdFromSeq(p(tilesKey)), logicalTreeNode, p)) - case _ => None + def instantiateTile(crossingLookup: (Seq[RocketCrossingParams], Int) => ClockCrossingType) + (implicit logicalTreeNode: LogicalTreeNode, p: Parameters) = { + val tileParams = p(tk) + val crossings = crossingLookup(p(ck), tileParams.size) + (tileParams zip crossings) map ((param, crossing) => ( + param, + crossing, + LazyModule(tileCtr(param, crossing, PriorityMuxHartIdFromSeq(tileParams), logicalTreeNode)) + )) } } -object CoreManager { - val cores: List[CoreEntryBase] = List( - // ADD YOUR CORE DEFINITION HERE - new CoreEntry[ArianeTileParams, ArianeTile](ArianeTilesKey, ArianeCrossingKey) - ) -} - // Core Generic Config - change properties in the given map class GenericConfig(properties: Map[String, Any], filterFunc: Any => Bool) { val configFunc: (View, View, View) => PartialFunction[Any, Any] = ((site, here, up) => key => { @@ -74,3 +71,10 @@ object GenericConfig { def apply(properties: Map[String, Any], filterFunc: Any => Bool = (_ => true)) = new GenericConfig(properties, filterFunc).configFunc } + +object CoreManager { + val cores: List[CoreEntryBase] = List( + // ADD YOUR CORE DEFINITION HERE + new CoreEntry[ArianeTileParams, ArianeTile](ArianeTilesKey, ArianeCrossingKey) + ) +} diff --git a/generators/chipyard/src/main/scala/Subsystem.scala b/generators/chipyard/src/main/scala/Subsystem.scala index 7b554d2a..c7924c9a 100644 --- a/generators/chipyard/src/main/scala/Subsystem.scala +++ b/generators/chipyard/src/main/scala/Subsystem.scala @@ -35,18 +35,25 @@ trait HasChipyardTiles extends HasTiles protected val rocketTileParams = p(RocketTilesKey) protected val boomTileParams = p(BoomTilesKey) - protected val coreTileParams = CoreRegistrar.cores map (coreType => p(coreType.tilesKey)) // crossing can either be per tile or global (aka only 1 crossing specified) private val rocketCrossings = perTileOrGlobalSetting(p(RocketCrossingKey), rocketTileParams.size) private val boomCrossings = perTileOrGlobalSetting(p(BoomCrossingKey), boomTileParams.size) - private val coreCrossings = (CoreRegistrar.cores zip coreTileParams) map (_ match { - case (coreType, tileParams) => perTileOrGlobalSetting(p(coreType.crossingKey), tileParams.size) - }) - // TODO: XXX The "tiles" below scan for hartId but it is not in CoreParams. Should that be added in later + private val rocketTilesInfo = (rocketTileParams zip rocketCrossings) map ((param, crossing) => ( + param, + crossing, + LazyModule(new RocketTile(param, crossing, PriorityMuxHartIdFromSeq(rocketTileParams), logicalTreeNode)) + )) + private val boomTilesInfo = (boomTileParams zip boomCrossings) map ((param, crossing) => ( + param, + crossing, + LazyModule(new RocketTile(param, crossing, PriorityMuxHartIdFromSeq(boomCrossings), logicalTreeNode)) + )) + + // TODO: XXX The "tiles" below scan for hartId but it is not in CoreParams. Should that be added in later // revision, or I have to use reflection to get that parameter? - val allTilesInfo = (rocketTileParams ++ boomTileParams ++ coreTileParams.flatten) zip (rocketCrossings ++ boomCrossings ++ coreCrossings.flatten) + val allTilesInfo = rocketTilesInfo ++ boomTilesInfo ++ (CoreManager.cores map _.instantiateTile(perTileOrGlobalSetting _)) // Make a tile and wire its nodes into the system, // according to the specified type of clock crossing. @@ -56,19 +63,7 @@ trait HasChipyardTiles extends HasTiles // There is something weird with registering tile-local interrupt controllers to the CLINT. // TODO: investigate why val tiles = allTilesInfo.sortWith(_._1.hartId < _._1.hartId).map { - case (param, crossing) => { - - val tile = param match { - case r: RocketTileParams => { - LazyModule(new RocketTile(r, crossing, PriorityMuxHartIdFromSeq(rocketTileParams), logicalTreeNode)) - } - case b: BoomTileParams => { - LazyModule(new BoomTile(b, crossing, PriorityMuxHartIdFromSeq(boomTileParams), logicalTreeNode)) - } - case _ => LazyModule( - (CoreRegistrar.cores collect (core => core.instantiateTile(param, crossing, paramList, logicalTreeNode, p)).unlift()) (0) - ) - } + case (param, crossing, tile) => { connectMasterPortsToSBus(tile, crossing) connectSlavePortsToCBus(tile, crossing) connectInterrupts(tile, debugOpt, clintOpt, plicOpt) @@ -77,7 +72,6 @@ trait HasChipyardTiles extends HasTiles } } - def coreMonitorBundles = tiles.map { case r: RocketTile => r.module.core.rocketImpl.coreMonitorBundle case b: BoomTile => b.module.core.coreMonitorBundle From a120edd36431edf382a7a5f22728420357e9c8f9 Mon Sep 17 00:00:00 2001 From: Zitao Fang Date: Mon, 25 May 2020 21:50:44 -0700 Subject: [PATCH 06/42] Pass Scala Compilation --- .../src/main/scala/ConfigFragments.scala | 3 +- .../chipyard/src/main/scala/CoreManager.scala | 57 ++++++++++--------- .../chipyard/src/main/scala/Subsystem.scala | 29 +++++----- .../chipyard/src/main/scala/TestSuites.scala | 6 +- .../scala/stage/phases/AddDefaultTests.scala | 4 +- 5 files changed, 53 insertions(+), 46 deletions(-) diff --git a/generators/chipyard/src/main/scala/ConfigFragments.scala b/generators/chipyard/src/main/scala/ConfigFragments.scala index e87b833a..697dc4ec 100644 --- a/generators/chipyard/src/main/scala/ConfigFragments.scala +++ b/generators/chipyard/src/main/scala/ConfigFragments.scala @@ -22,8 +22,7 @@ import sifive.blocks.devices.uart._ import sifive.blocks.devices.spi._ import chipyard.{BuildTop, BuildSystem} -import chipyard.{CoreRegistrar, CoreRegisterEntryBase} -import chipyard.hlist +import chipyard.GenericConfig /** * TODO: Why do we need this? diff --git a/generators/chipyard/src/main/scala/CoreManager.scala b/generators/chipyard/src/main/scala/CoreManager.scala index 39c3a678..d92f839c 100644 --- a/generators/chipyard/src/main/scala/CoreManager.scala +++ b/generators/chipyard/src/main/scala/CoreManager.scala @@ -7,7 +7,7 @@ import chisel3._ import freechips.rocketchip.config.{Parameters, Config, Field, View} import freechips.rocketchip.subsystem.{SystemBusKey, RocketTilesKey, RocketCrossingParams} -import freechips.rocketchip.diplomacy.LazyModule +import freechips.rocketchip.diplomacy.{LazyModule, ClockCrossingType, ValName} import freechips.rocketchip.diplomaticobjectmodel.logicaltree.LogicalTreeNode import freechips.rocketchip.rocket._ import freechips.rocketchip.tile._ @@ -16,59 +16,64 @@ import ariane.{ArianeTile, ArianeTilesKey, ArianeCrossingKey, ArianeTileParams} // Third-party core entries sealed trait CoreEntryBase { - def updateWithFilter(view: View, p: Any => View): (Map[String, Any] => PartialFunction[Any, Seq[AnyRef]]) - def instantiateTile(crossingLookup: (Seq[RocketCrossingParams], Int) => ClockCrossingType) - (implicit logicalTreeNode: LogicalTreeNode, p: Parameters): (CoreParams, ClockCrossingType, BaseTile) + def tileParamsLookup(implicit p: Parameters): Seq[TileParams] + def updateWithFilter(view: View, p: Any => Boolean): PartialFunction[Any, Map[String, Any] => Any] + def instantiateTile(crossingLookup: (Seq[RocketCrossingParams], Int) => Seq[RocketCrossingParams], logicalTreeNode: LogicalTreeNode) + (implicit p: Parameters, valName: ValName): Seq[(TileParams, RocketCrossingParams, BaseTile)] } -class CoreEntry[TileParamsT <: CoreParams, TileT <: BaseTile]( +class CoreEntry[TileParamsT <: TileParams with Product: TypeTag, TileT <: BaseTile : TypeTag]( tk: Field[Seq[TileParamsT]], ck: Field[Seq[RocketCrossingParams]] ) extends CoreEntryBase { private val mirror = runtimeMirror(getClass.getClassLoader) private val paramClass = mirror.runtimeClass(typeOf[TileParamsT].typeSymbol.asClass) - private val paramNames = Map((paramClass.getDeclaredFields map _.getName).zipWithIndex) + private val paramNames = (paramClass.getDeclaredFields map (f => f.getName)).zipWithIndex.toMap private val paramCtr = paramClass.getConstructors.head private val tileClass = mirror.runtimeClass(typeOf[TileT].typeSymbol.asClass) private val tileCtr = paramClass.getConstructors.head // copy() function in - def copyTileParam(tileParam: AnyRef, properties: Map[String, Any]) = { - val values = foo.productIterator.toList - val indexedProperties = properties map (key => (paramNames(key), properties(key))) + def copyTileParam(tileParam: TileParamsT, properties: Map[String, Any]) = { + val values = tileParam.productIterator.toList + val indexedProperties = properties map { case (key, value) => (paramNames(key), value) } val newValues = (0 until values.size) map - (i => if (indexedProperties contains i) indexedProperties(i) else values(i)) + (i => (if (indexedProperties contains i) indexedProperties(i) else values(i)).asInstanceOf[AnyRef]) paramCtr.newInstance(newValues:_*) } - def updateWithFilter(view: View, p: Any => View) = { - case key if (key == tk && p(tk)) => view(tk) map - (tile => properties => copyTileParam(tile, properties)) + def tileParamsLookup(implicit p: Parameters) = p(tk) + + def updateWithFilter(view: View, p: Any => Boolean): PartialFunction[Any, Map[String, Any] => Any] = { + case key if (key == tk && p(tk)) => properties => view(tk) map + (tile => copyTileParam(tile, properties)) } - def instantiateTile(crossingLookup: (Seq[RocketCrossingParams], Int) => ClockCrossingType) - (implicit logicalTreeNode: LogicalTreeNode, p: Parameters) = { + def instantiateTile(crossingLookup: (Seq[RocketCrossingParams], Int) => Seq[RocketCrossingParams], logicalTreeNode: LogicalTreeNode) + (implicit p: Parameters, valName: ValName) = { val tileParams = p(tk) val crossings = crossingLookup(p(ck), tileParams.size) - (tileParams zip crossings) map ((param, crossing) => ( - param, - crossing, - LazyModule(tileCtr(param, crossing, PriorityMuxHartIdFromSeq(tileParams), logicalTreeNode)) - )) + (tileParams zip crossings) map { + case (param, crossing) => ( + param, + crossing, + LazyModule(tileCtr.newInstance(param, crossing, PriorityMuxHartIdFromSeq(tileParams), logicalTreeNode).asInstanceOf[TileT]) + ) + } } } // Core Generic Config - change properties in the given map -class GenericConfig(properties: Map[String, Any], filterFunc: Any => Bool) { - val configFunc: (View, View, View) => PartialFunction[Any, Any] = ((site, here, up) => key => { - val tiles = CoreManager.cores flatMap _.updateWithFilter(up, filterFunc).lift(key) - if (tiles.size == 0) None else Some(tiles map _(properties)) - }).unlift +class GenericConfig(properties: Map[String, Any], filterFunc: Any => Boolean) { + val configFunc: (View, View, View) => PartialFunction[Any, Any] = (site, here, up) => scala.Function.unlift((key: Any) => { + val tiles = CoreManager.cores flatMap (core => core.updateWithFilter(up, filterFunc).lift(key)) + if (tiles.size == 0) None else Some(tiles map (tile => tile(properties))) + }) } object GenericConfig { - def apply(properties: Map[String, Any], filterFunc: Any => Bool = (_ => true)) = + def apply(properties: Map[String, Any], filterFunc: Any => Boolean = (_ => true)) = new GenericConfig(properties, filterFunc).configFunc } diff --git a/generators/chipyard/src/main/scala/Subsystem.scala b/generators/chipyard/src/main/scala/Subsystem.scala index c7924c9a..1b766099 100644 --- a/generators/chipyard/src/main/scala/Subsystem.scala +++ b/generators/chipyard/src/main/scala/Subsystem.scala @@ -40,20 +40,23 @@ trait HasChipyardTiles extends HasTiles private val rocketCrossings = perTileOrGlobalSetting(p(RocketCrossingKey), rocketTileParams.size) private val boomCrossings = perTileOrGlobalSetting(p(BoomCrossingKey), boomTileParams.size) - private val rocketTilesInfo = (rocketTileParams zip rocketCrossings) map ((param, crossing) => ( - param, - crossing, - LazyModule(new RocketTile(param, crossing, PriorityMuxHartIdFromSeq(rocketTileParams), logicalTreeNode)) - )) - private val boomTilesInfo = (boomTileParams zip boomCrossings) map ((param, crossing) => ( - param, - crossing, - LazyModule(new RocketTile(param, crossing, PriorityMuxHartIdFromSeq(boomCrossings), logicalTreeNode)) - )) + private val rocketTilesInfo = (rocketTileParams zip rocketCrossings) map { + case (param, crossing) => ( + param, + crossing, + LazyModule(new RocketTile(param, crossing, PriorityMuxHartIdFromSeq(rocketTileParams), logicalTreeNode)) + ) + } + private val boomTilesInfo = (boomTileParams zip boomCrossings) map { + case (param, crossing) => ( + param, + crossing, + LazyModule(new BoomTile(param, crossing, PriorityMuxHartIdFromSeq(boomTileParams), logicalTreeNode)) + ) + } - // TODO: XXX The "tiles" below scan for hartId but it is not in CoreParams. Should that be added in later - // revision, or I have to use reflection to get that parameter? - val allTilesInfo = rocketTilesInfo ++ boomTilesInfo ++ (CoreManager.cores map _.instantiateTile(perTileOrGlobalSetting _)) + val allTilesInfo = rocketTilesInfo ++ boomTilesInfo ++ + (CoreManager.cores flatMap (core => core.instantiateTile(perTileOrGlobalSetting _, logicalTreeNode))) // Make a tile and wire its nodes into the system, // according to the specified type of clock crossing. diff --git a/generators/chipyard/src/main/scala/TestSuites.scala b/generators/chipyard/src/main/scala/TestSuites.scala index a4944355..9041be61 100644 --- a/generators/chipyard/src/main/scala/TestSuites.scala +++ b/generators/chipyard/src/main/scala/TestSuites.scala @@ -3,7 +3,7 @@ package chipyard import scala.collection.mutable.{LinkedHashSet} import freechips.rocketchip.subsystem.{RocketTilesKey} -import freechips.rocketchip.tile.{XLen, CoreParams} +import freechips.rocketchip.tile.{XLen, TileParams} import freechips.rocketchip.config.{Parameters, Field} import freechips.rocketchip.system.{TestGeneration, RegressionTestSuite, RocketTestSuite} @@ -145,9 +145,9 @@ class TestSuiteHelper /** * Add third-party core (including Ariane) tests (asm, bmark, regression) */ - def addThirdPartyTestSuites[TileParams <: CoreParams](tilesKey: Field[Seq[TileParams]])(implicit p: Parameters) = { + def addThirdPartyTestSuites(tiles: Seq[TileParams])(implicit p: Parameters) = { val xlen = p(XLen) - p(tilesKey).asInstanceOf[Seq[CoreParams]].find(_.hartId == 0).map { tileParams => + tiles.find(_.hartId == 0).map { tileParams => val coreParams = tileParams.core val vm = coreParams.useVM val env = if (vm) List("p","v") else List("p") diff --git a/generators/chipyard/src/main/scala/stage/phases/AddDefaultTests.scala b/generators/chipyard/src/main/scala/stage/phases/AddDefaultTests.scala index 3d367ffa..cbd2e1a7 100644 --- a/generators/chipyard/src/main/scala/stage/phases/AddDefaultTests.scala +++ b/generators/chipyard/src/main/scala/stage/phases/AddDefaultTests.scala @@ -17,7 +17,7 @@ import freechips.rocketchip.stage.phases.{RocketTestSuiteAnnotation} import freechips.rocketchip.system.{RocketTestSuite, TestGeneration} import freechips.rocketchip.util.HasRocketChipStageUtils -import chipyard.{TestSuiteHelper, CoreRegistrar} +import chipyard.{TestSuiteHelper, CoreManager} 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 @@ -32,7 +32,7 @@ class AddDefaultTests extends Phase with PreservesAll[Phase] with HasRocketChipS val suiteHelper = new TestSuiteHelper suiteHelper.addRocketTestSuites suiteHelper.addBoomTestSuites - CoreRegistrar.cores map suiteHelper.addThirdPartyTestSuites(_.tilesKey) + CoreManager.cores map (core => suiteHelper.addThirdPartyTestSuites(core.tileParamsLookup)) // if hwacha parameter exists then generate its tests // TODO: find a more elegant way to do this. either through From 8f39791d940e748d0a25c06a957b0b9fd40e275c Mon Sep 17 00:00:00 2001 From: Zitao Fang Date: Thu, 28 May 2020 22:46:13 -0700 Subject: [PATCH 07/42] Git ignores vscode and scala plugins --- .gitignore | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.gitignore b/.gitignore index 47cb4d87..eaddd6e1 100644 --- a/.gitignore +++ b/.gitignore @@ -10,6 +10,10 @@ target *# *~ .idea +.bloop +.metals +project/metals.sbt +.vscode .DS_Store env.sh riscv-tools-install From 71bac7b7c9f28a47662c2334914faaf8606744a9 Mon Sep 17 00:00:00 2001 From: Zitao Fang Date: Fri, 29 May 2020 20:23:53 -0700 Subject: [PATCH 08/42] Fixed runtime error --- generators/chipyard/src/main/scala/CoreManager.scala | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/generators/chipyard/src/main/scala/CoreManager.scala b/generators/chipyard/src/main/scala/CoreManager.scala index d92f839c..22212795 100644 --- a/generators/chipyard/src/main/scala/CoreManager.scala +++ b/generators/chipyard/src/main/scala/CoreManager.scala @@ -13,8 +13,9 @@ import freechips.rocketchip.rocket._ import freechips.rocketchip.tile._ import ariane.{ArianeTile, ArianeTilesKey, ArianeCrossingKey, ArianeTileParams} +import chipsalliance.rocketchip.config.Parameters -// Third-party core entries +// Base trait for all third-party core entries sealed trait CoreEntryBase { def tileParamsLookup(implicit p: Parameters): Seq[TileParams] def updateWithFilter(view: View, p: Any => Boolean): PartialFunction[Any, Map[String, Any] => Any] @@ -22,6 +23,7 @@ sealed trait CoreEntryBase { (implicit p: Parameters, valName: ValName): Seq[(TileParams, RocketCrossingParams, BaseTile)] } +// Implementation of third-party core entries class CoreEntry[TileParamsT <: TileParams with Product: TypeTag, TileT <: BaseTile : TypeTag]( tk: Field[Seq[TileParamsT]], ck: Field[Seq[RocketCrossingParams]] @@ -32,9 +34,9 @@ class CoreEntry[TileParamsT <: TileParams with Product: TypeTag, TileT <: BaseTi private val paramCtr = paramClass.getConstructors.head private val tileClass = mirror.runtimeClass(typeOf[TileT].typeSymbol.asClass) - private val tileCtr = paramClass.getConstructors.head + private val tileCtr = tileClass.getConstructors.head - // copy() function in + // Reflective version of copy() def copyTileParam(tileParam: TileParamsT, properties: Map[String, Any]) = { val values = tileParam.productIterator.toList val indexedProperties = properties map { case (key, value) => (paramNames(key), value) } @@ -58,7 +60,7 @@ class CoreEntry[TileParamsT <: TileParams with Product: TypeTag, TileT <: BaseTi case (param, crossing) => ( param, crossing, - LazyModule(tileCtr.newInstance(param, crossing, PriorityMuxHartIdFromSeq(tileParams), logicalTreeNode).asInstanceOf[TileT]) + LazyModule(tileCtr.newInstance(param, crossing, PriorityMuxHartIdFromSeq(tileParams), logicalTreeNode, p.asInstanceOf[Parameters]).asInstanceOf[TileT]) ) } } From 3fcfc133b1a4e1840ca7f6cd08fd5eb43938aaab Mon Sep 17 00:00:00 2001 From: Zitao Fang Date: Sun, 31 May 2020 10:51:11 -0700 Subject: [PATCH 09/42] Add Rocket and Boom to CoreManager --- .../src/main/scala/ConfigFragments.scala | 6 +- .../chipyard/src/main/scala/CoreManager.scala | 7 +- .../chipyard/src/main/scala/Subsystem.scala | 24 +----- .../chipyard/src/main/scala/TestSuites.scala | 81 +------------------ .../scala/stage/phases/AddDefaultTests.scala | 5 +- 5 files changed, 12 insertions(+), 111 deletions(-) diff --git a/generators/chipyard/src/main/scala/ConfigFragments.scala b/generators/chipyard/src/main/scala/ConfigFragments.scala index 697dc4ec..dfe225e4 100644 --- a/generators/chipyard/src/main/scala/ConfigFragments.scala +++ b/generators/chipyard/src/main/scala/ConfigFragments.scala @@ -148,7 +148,9 @@ class WithControlCore extends Config((site, here, up) => { }) class WithTraceIO extends Config((site, here, up) => - GenericConfig(Map("trace" -> true)) (site, here, up) orElse { - case BoomTilesKey => up(BoomTilesKey) map (tile => tile.copy(trace = true)) + GenericConfig(Map("trace" -> true), { + case RocketTilesKey => false + case _ => true + }) (site, here, up) orElse { case TracePortKey => Some(TracePortParams()) }) diff --git a/generators/chipyard/src/main/scala/CoreManager.scala b/generators/chipyard/src/main/scala/CoreManager.scala index 22212795..ec467d8f 100644 --- a/generators/chipyard/src/main/scala/CoreManager.scala +++ b/generators/chipyard/src/main/scala/CoreManager.scala @@ -6,12 +6,13 @@ import scala.reflect.runtime.universe._ import chisel3._ import freechips.rocketchip.config.{Parameters, Config, Field, View} -import freechips.rocketchip.subsystem.{SystemBusKey, RocketTilesKey, RocketCrossingParams} +import freechips.rocketchip.subsystem.{SystemBusKey, RocketTilesKey, RocketCrossingParams, RocketCrossingKey} import freechips.rocketchip.diplomacy.{LazyModule, ClockCrossingType, ValName} import freechips.rocketchip.diplomaticobjectmodel.logicaltree.LogicalTreeNode import freechips.rocketchip.rocket._ import freechips.rocketchip.tile._ +import boom.common.{BoomTile, BoomTilesKey, BoomCrossingKey, BoomTileParams} import ariane.{ArianeTile, ArianeTilesKey, ArianeCrossingKey, ArianeTileParams} import chipsalliance.rocketchip.config.Parameters @@ -34,7 +35,7 @@ class CoreEntry[TileParamsT <: TileParams with Product: TypeTag, TileT <: BaseTi private val paramCtr = paramClass.getConstructors.head private val tileClass = mirror.runtimeClass(typeOf[TileT].typeSymbol.asClass) - private val tileCtr = tileClass.getConstructors.head + private val tileCtr = tileClass.getConstructors.filter(ctr => ctr.getParameterTypes()(4) == classOf[Parameters]).head // Reflective version of copy() def copyTileParam(tileParam: TileParamsT, properties: Map[String, Any]) = { @@ -82,6 +83,8 @@ object GenericConfig { object CoreManager { val cores: List[CoreEntryBase] = List( // ADD YOUR CORE DEFINITION HERE + new CoreEntry[RocketTileParams, RocketTile](RocketTilesKey, RocketCrossingKey), + new CoreEntry[BoomTileParams, BoomTile](BoomTilesKey, BoomCrossingKey), new CoreEntry[ArianeTileParams, ArianeTile](ArianeTilesKey, ArianeCrossingKey) ) } diff --git a/generators/chipyard/src/main/scala/Subsystem.scala b/generators/chipyard/src/main/scala/Subsystem.scala index 1b766099..889e5f6f 100644 --- a/generators/chipyard/src/main/scala/Subsystem.scala +++ b/generators/chipyard/src/main/scala/Subsystem.scala @@ -33,29 +33,7 @@ trait HasChipyardTiles extends HasTiles val module: HasChipyardTilesModuleImp - protected val rocketTileParams = p(RocketTilesKey) - protected val boomTileParams = p(BoomTilesKey) - - // crossing can either be per tile or global (aka only 1 crossing specified) - private val rocketCrossings = perTileOrGlobalSetting(p(RocketCrossingKey), rocketTileParams.size) - private val boomCrossings = perTileOrGlobalSetting(p(BoomCrossingKey), boomTileParams.size) - - private val rocketTilesInfo = (rocketTileParams zip rocketCrossings) map { - case (param, crossing) => ( - param, - crossing, - LazyModule(new RocketTile(param, crossing, PriorityMuxHartIdFromSeq(rocketTileParams), logicalTreeNode)) - ) - } - private val boomTilesInfo = (boomTileParams zip boomCrossings) map { - case (param, crossing) => ( - param, - crossing, - LazyModule(new BoomTile(param, crossing, PriorityMuxHartIdFromSeq(boomTileParams), logicalTreeNode)) - ) - } - - val allTilesInfo = rocketTilesInfo ++ boomTilesInfo ++ + val allTilesInfo: Seq[(TileParams, RocketCrossingParams, BaseTile)] = (CoreManager.cores flatMap (core => core.instantiateTile(perTileOrGlobalSetting _, logicalTreeNode))) // Make a tile and wire its nodes into the system, diff --git a/generators/chipyard/src/main/scala/TestSuites.scala b/generators/chipyard/src/main/scala/TestSuites.scala index 9041be61..6fba4b2a 100644 --- a/generators/chipyard/src/main/scala/TestSuites.scala +++ b/generators/chipyard/src/main/scala/TestSuites.scala @@ -62,86 +62,6 @@ class TestSuiteHelper def addSuite(s: RocketTestSuite) { suites += (s.makeTargetName -> s) } def addSuites(s: Seq[RocketTestSuite]) { s.foreach(addSuite) } - /** - * Add BOOM tests (asm, bmark, regression) - */ - def addBoomTestSuites(implicit p: Parameters) = { - val xlen = p(XLen) - p(BoomTilesKey).find(_.hartId == 0).map { tileParams => - val coreParams = tileParams.core - val vm = coreParams.useVM - val env = if (vm) List("p","v") else List("p") - coreParams.fpu foreach { case cfg => - if (xlen == 32) { - addSuites(env.map(rv32uf)) - if (cfg.fLen >= 64) { - addSuites(env.map(rv32ud)) - } - } else if (cfg.fLen >= 64) { - addSuites(env.map(rv64ud)) - addSuites(env.map(rv64uf)) - addSuite(rv32udBenchmarks) - } - } - if (coreParams.useAtomics) { - if (tileParams.dcache.flatMap(_.scratch).isEmpty) { - addSuites(env.map(if (xlen == 64) rv64ua else rv32ua)) - } else { - addSuites(env.map(if (xlen == 64) rv64uaSansLRSC else rv32uaSansLRSC)) - } - } - if (coreParams.useCompressed) addSuites(env.map(if (xlen == 64) rv64uc else rv32uc)) - val (rvi, rvu) = - if (xlen == 64) ((if (vm) rv64i else rv64pi), rv64u) - else ((if (vm) rv32i else rv32pi), rv32u) - - addSuites(rvi.map(_("p"))) - addSuites(rvu.map(_("p"))) - addSuites((if (vm) List("v") else List()).flatMap(env => rvu.map(_(env)))) - addSuite(benchmarks) - addSuite(new RegressionTestSuite(if (xlen == 64) rv64RegrTestNames else rv32RegrTestNames)) - } - } - - /** - * Add Rocket tests (asm, bmark, regression) - */ - def addRocketTestSuites(implicit p: Parameters) = { - val xlen = p(XLen) - p(RocketTilesKey).find(_.hartId == 0).map { tileParams => - val coreParams = tileParams.core - val vm = coreParams.useVM - val env = if (vm) List("p","v") else List("p") - coreParams.fpu foreach { case cfg => - if (xlen == 32) { - addSuites(env.map(rv32uf)) - if (cfg.fLen >= 64) - addSuites(env.map(rv32ud)) - } else { - addSuite(rv32udBenchmarks) - addSuites(env.map(rv64uf)) - if (cfg.fLen >= 64) - addSuites(env.map(rv64ud)) - } - } - if (coreParams.useAtomics) { - if (tileParams.dcache.flatMap(_.scratch).isEmpty) - addSuites(env.map(if (xlen == 64) rv64ua else rv32ua)) - else - addSuites(env.map(if (xlen == 64) rv64uaSansLRSC else rv32uaSansLRSC)) - } - if (coreParams.useCompressed) addSuites(env.map(if (xlen == 64) rv64uc else rv32uc)) - val (rvi, rvu) = - if (xlen == 64) ((if (vm) rv64i else rv64pi), rv64u) - else ((if (vm) rv32i else rv32pi), rv32u) - - addSuites(rvi.map(_("p"))) - addSuites((if (vm) List("v") else List()).flatMap(env => rvu.map(_(env)))) - addSuite(benchmarks) - addSuite(new RegressionTestSuite(if (xlen == 64) rv64RegrTestNames else rv32RegrTestNames)) - } - } - /** * Add third-party core (including Ariane) tests (asm, bmark, regression) */ @@ -175,6 +95,7 @@ class TestSuiteHelper else ((if (vm) rv32i else rv32pi), rv32u) addSuites(rvi.map(_("p"))) + addSuites(rvu.map(_("p"))) addSuites((if (vm) List("v") else List()).flatMap(env => rvu.map(_(env)))) addSuite(benchmarks) addSuite(new RegressionTestSuite(if (xlen == 64) rv64RegrTestNames else rv32RegrTestNames)) diff --git a/generators/chipyard/src/main/scala/stage/phases/AddDefaultTests.scala b/generators/chipyard/src/main/scala/stage/phases/AddDefaultTests.scala index 464c8ff5..f8ae3177 100644 --- a/generators/chipyard/src/main/scala/stage/phases/AddDefaultTests.scala +++ b/generators/chipyard/src/main/scala/stage/phases/AddDefaultTests.scala @@ -33,11 +33,8 @@ 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) { - suiteHelper.addRocketTestSuites - suiteHelper.addBoomTestSuites + if (p.lift(XLen).nonEmpty) CoreManager.cores map (core => suiteHelper.addThirdPartyTestSuites(core.tileParamsLookup)) - } // if hwacha parameter exists then generate its tests // TODO: find a more elegant way to do this. either through From 0743abd9db6446f5194c6dc5f4425a2d93794c80 Mon Sep 17 00:00:00 2001 From: Zitao Fang Date: Sun, 31 May 2020 15:09:22 -0700 Subject: [PATCH 10/42] Add comments --- generators/chipyard/src/main/scala/CoreManager.scala | 11 +++++++++-- generators/chipyard/src/main/scala/Subsystem.scala | 3 ++- generators/chipyard/src/main/scala/TestSuites.scala | 4 ++-- .../src/main/scala/stage/phases/AddDefaultTests.scala | 4 ++-- 4 files changed, 15 insertions(+), 7 deletions(-) diff --git a/generators/chipyard/src/main/scala/CoreManager.scala b/generators/chipyard/src/main/scala/CoreManager.scala index ec467d8f..ecee820f 100644 --- a/generators/chipyard/src/main/scala/CoreManager.scala +++ b/generators/chipyard/src/main/scala/CoreManager.scala @@ -29,15 +29,17 @@ class CoreEntry[TileParamsT <: TileParams with Product: TypeTag, TileT <: BaseTi tk: Field[Seq[TileParamsT]], ck: Field[Seq[RocketCrossingParams]] ) extends CoreEntryBase { + // Use reflection to get the parameter's constructor private val mirror = runtimeMirror(getClass.getClassLoader) private val paramClass = mirror.runtimeClass(typeOf[TileParamsT].typeSymbol.asClass) private val paramNames = (paramClass.getDeclaredFields map (f => f.getName)).zipWithIndex.toMap private val paramCtr = paramClass.getConstructors.head + // Use reflection to get the tile's constructor private val tileClass = mirror.runtimeClass(typeOf[TileT].typeSymbol.asClass) private val tileCtr = tileClass.getConstructors.filter(ctr => ctr.getParameterTypes()(4) == classOf[Parameters]).head - // Reflective version of copy() + // Version of case class' copy() using reflection, where fields to be updated are passed by a map def copyTileParam(tileParam: TileParamsT, properties: Map[String, Any]) = { val values = tileParam.productIterator.toList val indexedProperties = properties map { case (key, value) => (paramNames(key), value) } @@ -46,13 +48,16 @@ class CoreEntry[TileParamsT <: TileParams with Product: TypeTag, TileT <: BaseTi paramCtr.newInstance(newValues:_*) } + // Tile parameter lookup using correct type def tileParamsLookup(implicit p: Parameters) = p(tk) + // If this core meet the requirement given by p, update parameter fields in the map def updateWithFilter(view: View, p: Any => Boolean): PartialFunction[Any, Map[String, Any] => Any] = { case key if (key == tk && p(tk)) => properties => view(tk) map (tile => copyTileParam(tile, properties)) } + // 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) = { val tileParams = p(tk) @@ -75,14 +80,16 @@ class GenericConfig(properties: Map[String, Any], filterFunc: Any => Boolean) { }) } +// Wrapper object of the class above object GenericConfig { def apply(properties: Map[String, Any], filterFunc: Any => Boolean = (_ => true)) = new GenericConfig(properties, filterFunc).configFunc } +// A list of all cores. object CoreManager { val cores: List[CoreEntryBase] = List( - // ADD YOUR CORE DEFINITION HERE + // TODO ADD YOUR CORE DEFINITION HERE new CoreEntry[RocketTileParams, RocketTile](RocketTilesKey, RocketCrossingKey), new CoreEntry[BoomTileParams, BoomTile](BoomTilesKey, BoomCrossingKey), new CoreEntry[ArianeTileParams, ArianeTile](ArianeTilesKey, ArianeCrossingKey) diff --git a/generators/chipyard/src/main/scala/Subsystem.scala b/generators/chipyard/src/main/scala/Subsystem.scala index 889e5f6f..6410ac4e 100644 --- a/generators/chipyard/src/main/scala/Subsystem.scala +++ b/generators/chipyard/src/main/scala/Subsystem.scala @@ -33,7 +33,8 @@ trait HasChipyardTiles extends HasTiles val module: HasChipyardTilesModuleImp - val allTilesInfo: Seq[(TileParams, RocketCrossingParams, BaseTile)] = + // Generate tiles info from the list of cores in CoreManager + val allTilesInfo: Seq[(TileParams, RocketCrossingParams, BaseTile)] = (CoreManager.cores flatMap (core => core.instantiateTile(perTileOrGlobalSetting _, logicalTreeNode))) // Make a tile and wire its nodes into the system, diff --git a/generators/chipyard/src/main/scala/TestSuites.scala b/generators/chipyard/src/main/scala/TestSuites.scala index 6fba4b2a..2261000f 100644 --- a/generators/chipyard/src/main/scala/TestSuites.scala +++ b/generators/chipyard/src/main/scala/TestSuites.scala @@ -63,9 +63,9 @@ class TestSuiteHelper def addSuites(s: Seq[RocketTestSuite]) { s.foreach(addSuite) } /** - * Add third-party core (including Ariane) tests (asm, bmark, regression) + * Add generic tests (asm, bmark, regression) for all cores. */ - def addThirdPartyTestSuites(tiles: Seq[TileParams])(implicit p: Parameters) = { + def addGenericTestSuites(tiles: Seq[TileParams])(implicit p: Parameters) = { val xlen = p(XLen) tiles.find(_.hartId == 0).map { tileParams => val coreParams = tileParams.core diff --git a/generators/chipyard/src/main/scala/stage/phases/AddDefaultTests.scala b/generators/chipyard/src/main/scala/stage/phases/AddDefaultTests.scala index f8ae3177..a36131b1 100644 --- a/generators/chipyard/src/main/scala/stage/phases/AddDefaultTests.scala +++ b/generators/chipyard/src/main/scala/stage/phases/AddDefaultTests.scala @@ -22,7 +22,7 @@ import chipyard.{TestSuiteHelper, CoreManager} 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 - // because the RocketTestSuiteAnnotation is not serializable (but is not marked as such). + // because the RocketTestSuiteAnnotation is not serializable (but is not marked as such). override val prerequisites = Seq( Dependency[freechips.rocketchip.stage.phases.GenerateFirrtlAnnos], Dependency[freechips.rocketchip.stage.phases.AddDefaultTests]) @@ -34,7 +34,7 @@ class AddDefaultTests extends Phase with PreservesAll[Phase] with HasRocketChipS // 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) - CoreManager.cores map (core => suiteHelper.addThirdPartyTestSuites(core.tileParamsLookup)) + CoreManager.cores 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 From aa606e580a60515fdc375c30b9ace5b074efd8fc Mon Sep 17 00:00:00 2001 From: Zitao Fang Date: Mon, 1 Jun 2020 18:41:21 -0700 Subject: [PATCH 11/42] Change names --- .../src/main/scala/ConfigFragments.scala | 13 +++--- .../chipyard/src/main/scala/CoreManager.scala | 46 ++++++++++--------- 2 files changed, 30 insertions(+), 29 deletions(-) diff --git a/generators/chipyard/src/main/scala/ConfigFragments.scala b/generators/chipyard/src/main/scala/ConfigFragments.scala index dfe225e4..cad47f72 100644 --- a/generators/chipyard/src/main/scala/ConfigFragments.scala +++ b/generators/chipyard/src/main/scala/ConfigFragments.scala @@ -22,7 +22,7 @@ import sifive.blocks.devices.uart._ import sifive.blocks.devices.spi._ import chipyard.{BuildTop, BuildSystem} -import chipyard.GenericConfig +import chipyard.GenericCoreConfig /** * TODO: Why do we need this? @@ -147,10 +147,9 @@ class WithControlCore extends Config((site, here, up) => { case MaxHartIdBits => log2Up(up(RocketTilesKey, site).size + up(BoomTilesKey, site).size + 1) }) -class WithTraceIO extends Config((site, here, up) => - GenericConfig(Map("trace" -> true), { - case RocketTilesKey => false - case _ => true - }) (site, here, up) orElse { +class WithTraceIO extends GenericCoreConfig( + properties = Map("trace" -> true), + specialCase = (site, here, up) => { case TracePortKey => Some(TracePortParams()) - }) + } +) \ No newline at end of file diff --git a/generators/chipyard/src/main/scala/CoreManager.scala b/generators/chipyard/src/main/scala/CoreManager.scala index ecee820f..2756a42b 100644 --- a/generators/chipyard/src/main/scala/CoreManager.scala +++ b/generators/chipyard/src/main/scala/CoreManager.scala @@ -26,65 +26,67 @@ sealed trait CoreEntryBase { // Implementation of third-party core entries class CoreEntry[TileParamsT <: TileParams with Product: TypeTag, TileT <: BaseTile : TypeTag]( - tk: Field[Seq[TileParamsT]], - ck: Field[Seq[RocketCrossingParams]] + tilesKey: Field[Seq[TileParamsT]], + crossingKey: Field[Seq[RocketCrossingParams]] ) extends CoreEntryBase { // Use reflection to get the parameter's constructor private val mirror = runtimeMirror(getClass.getClassLoader) private val paramClass = mirror.runtimeClass(typeOf[TileParamsT].typeSymbol.asClass) private val paramNames = (paramClass.getDeclaredFields map (f => f.getName)).zipWithIndex.toMap - private val paramCtr = paramClass.getConstructors.head + private val paramCtor = paramClass.getConstructors.head // Use reflection to get the tile's constructor private val tileClass = mirror.runtimeClass(typeOf[TileT].typeSymbol.asClass) - private val tileCtr = tileClass.getConstructors.filter(ctr => ctr.getParameterTypes()(4) == classOf[Parameters]).head + private val tileCtor = tileClass.getConstructors.filter(ctor => ctor.getParameterTypes()(4) == classOf[Parameters]).head // Version of case class' copy() using reflection, where fields to be updated are passed by a map def copyTileParam(tileParam: TileParamsT, properties: Map[String, Any]) = { val values = tileParam.productIterator.toList - val indexedProperties = properties map { case (key, value) => (paramNames(key), value) } + //val filteredProperties = properties filter { case (key, value) => paramNames contains key } + val indexedProperties = /*filteredProperties*/ properties map { case (key, value) => (paramNames(key), value) } val newValues = (0 until values.size) map (i => (if (indexedProperties contains i) indexedProperties(i) else values(i)).asInstanceOf[AnyRef]) - paramCtr.newInstance(newValues:_*) + paramCtor.newInstance(newValues:_*) } // Tile parameter lookup using correct type - def tileParamsLookup(implicit p: Parameters) = p(tk) + def tileParamsLookup(implicit p: Parameters) = p(tilesKey) // If this core meet the requirement given by p, update parameter fields in the map def updateWithFilter(view: View, p: Any => Boolean): PartialFunction[Any, Map[String, Any] => Any] = { - case key if (key == tk && p(tk)) => properties => view(tk) map + case key if (key == tilesKey && p(tilesKey)) => properties => view(tilesKey) map (tile => copyTileParam(tile, properties)) } // 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) = { - val tileParams = p(tk) - val crossings = crossingLookup(p(ck), tileParams.size) + val tileParams = p(tilesKey) + val crossings = crossingLookup(p(crossingKey), tileParams.size) (tileParams zip crossings) map { case (param, crossing) => ( param, crossing, - LazyModule(tileCtr.newInstance(param, crossing, PriorityMuxHartIdFromSeq(tileParams), logicalTreeNode, p.asInstanceOf[Parameters]).asInstanceOf[TileT]) + LazyModule(tileCtor.newInstance(param, crossing, PriorityMuxHartIdFromSeq(tileParams), logicalTreeNode, p.asInstanceOf[Parameters]).asInstanceOf[TileT]) ) } } } -// Core Generic Config - change properties in the given map -class GenericConfig(properties: Map[String, Any], filterFunc: Any => Boolean) { - val configFunc: (View, View, View) => PartialFunction[Any, Any] = (site, here, up) => scala.Function.unlift((key: Any) => { +// Generic Core Config - change properties in the given map +class GenericCoreConfig( + // Parameter properties to be changed and their new values. Any field not in a core's parameters will be ignored. + properties: Map[String, Any], + // Function for filtering the list of TilesKey. + filterFunc: Any => Boolean = (_ => true), + // Handling special cases where partial function input is not a TilesKey. + specialCase: (View, View, View) => PartialFunction[Any, Any] = ((_, _, _) => Map.empty) +) extends Config((site, here, up) => + scala.Function.unlift((key: Any) => { val tiles = CoreManager.cores flatMap (core => core.updateWithFilter(up, filterFunc).lift(key)) if (tiles.size == 0) None else Some(tiles map (tile => tile(properties))) - }) -} - -// Wrapper object of the class above -object GenericConfig { - def apply(properties: Map[String, Any], filterFunc: Any => Boolean = (_ => true)) = - new GenericConfig(properties, filterFunc).configFunc -} + }).orElse(specialCase(site, here, up)) +) // A list of all cores. object CoreManager { From 02c8aac346df1f889fa7d4810a76b3db2daedd67 Mon Sep 17 00:00:00 2001 From: Zitao Fang Date: Wed, 3 Jun 2020 20:22:41 -0700 Subject: [PATCH 12/42] Revised generic config --- .../src/main/scala/ConfigFragments.scala | 11 +- .../chipyard/src/main/scala/CoreManager.scala | 47 ++----- .../src/main/scala/GenericCoreConfig.scala | 133 ++++++++++++++++++ .../scala/stage/phases/AddDefaultTests.scala | 11 +- 4 files changed, 153 insertions(+), 49 deletions(-) create mode 100644 generators/chipyard/src/main/scala/GenericCoreConfig.scala diff --git a/generators/chipyard/src/main/scala/ConfigFragments.scala b/generators/chipyard/src/main/scala/ConfigFragments.scala index cad47f72..4d0e0725 100644 --- a/generators/chipyard/src/main/scala/ConfigFragments.scala +++ b/generators/chipyard/src/main/scala/ConfigFragments.scala @@ -59,14 +59,7 @@ 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 RocketTilesKey => up(RocketTilesKey) map (tile => tile.copy( - core = tile.core.copy(nL2TLBEntries = entries) - )) - case BoomTilesKey => up(BoomTilesKey) map (tile => tile.copy( - core = tile.core.copy(nL2TLBEntries = entries) - )) -}) +class WithL2TLBs(entries: Int) extends GenericCoreConfig(Map("core" -> Map("nL2TLBEntries" -> entries))) class WithTracegenSystem extends Config((site, here, up) => { case BuildSystem => (p: Parameters) => LazyModule(new tracegen.TraceGenSystem()(p)) @@ -148,7 +141,7 @@ class WithControlCore extends Config((site, here, up) => { }) class WithTraceIO extends GenericCoreConfig( - properties = Map("trace" -> true), + newValues = Map("trace" -> true), specialCase = (site, here, up) => { case TracePortKey => Some(TracePortParams()) } diff --git a/generators/chipyard/src/main/scala/CoreManager.scala b/generators/chipyard/src/main/scala/CoreManager.scala index 2756a42b..57b63743 100644 --- a/generators/chipyard/src/main/scala/CoreManager.scala +++ b/generators/chipyard/src/main/scala/CoreManager.scala @@ -14,10 +14,10 @@ import freechips.rocketchip.tile._ import boom.common.{BoomTile, BoomTilesKey, BoomCrossingKey, BoomTileParams} import ariane.{ArianeTile, ArianeTilesKey, ArianeCrossingKey, ArianeTileParams} -import chipsalliance.rocketchip.config.Parameters // Base trait for all third-party core entries sealed trait CoreEntryBase { + val name: String def tileParamsLookup(implicit p: Parameters): Seq[TileParams] def updateWithFilter(view: View, p: Any => Boolean): PartialFunction[Any, Map[String, Any] => Any] def instantiateTile(crossingLookup: (Seq[RocketCrossingParams], Int) => Seq[RocketCrossingParams], logicalTreeNode: LogicalTreeNode) @@ -26,36 +26,22 @@ sealed trait CoreEntryBase { // Implementation of third-party core entries class CoreEntry[TileParamsT <: TileParams with Product: TypeTag, TileT <: BaseTile : TypeTag]( + val name: String, tilesKey: Field[Seq[TileParamsT]], crossingKey: Field[Seq[RocketCrossingParams]] ) extends CoreEntryBase { - // Use reflection to get the parameter's constructor - private val mirror = runtimeMirror(getClass.getClassLoader) - private val paramClass = mirror.runtimeClass(typeOf[TileParamsT].typeSymbol.asClass) - private val paramNames = (paramClass.getDeclaredFields map (f => f.getName)).zipWithIndex.toMap - private val paramCtor = paramClass.getConstructors.head - // Use reflection to get the tile's constructor + private val mirror = runtimeMirror(getClass.getClassLoader) private val tileClass = mirror.runtimeClass(typeOf[TileT].typeSymbol.asClass) private val tileCtor = tileClass.getConstructors.filter(ctor => ctor.getParameterTypes()(4) == classOf[Parameters]).head - // Version of case class' copy() using reflection, where fields to be updated are passed by a map - def copyTileParam(tileParam: TileParamsT, properties: Map[String, Any]) = { - val values = tileParam.productIterator.toList - //val filteredProperties = properties filter { case (key, value) => paramNames contains key } - val indexedProperties = /*filteredProperties*/ properties map { case (key, value) => (paramNames(key), value) } - val newValues = (0 until values.size) map - (i => (if (indexedProperties contains i) indexedProperties(i) else values(i)).asInstanceOf[AnyRef]) - paramCtor.newInstance(newValues:_*) - } - // Tile parameter lookup using correct type def tileParamsLookup(implicit p: Parameters) = p(tilesKey) // If this core meet the requirement given by p, update parameter fields in the map def updateWithFilter(view: View, p: Any => Boolean): PartialFunction[Any, Map[String, Any] => Any] = { - case key if (key == tilesKey && p(tilesKey)) => properties => view(tilesKey) map - (tile => copyTileParam(tile, properties)) + case key if (key == tilesKey && p(tilesKey)) => newValues => view(tilesKey) map + (tile => CopyParam(tile, newValues)) } // Instantiate a tile and zip it with its parameter info, used by subsystem @@ -73,27 +59,12 @@ class CoreEntry[TileParamsT <: TileParams with Product: TypeTag, TileT <: BaseTi } } -// Generic Core Config - change properties in the given map -class GenericCoreConfig( - // Parameter properties to be changed and their new values. Any field not in a core's parameters will be ignored. - properties: Map[String, Any], - // Function for filtering the list of TilesKey. - filterFunc: Any => Boolean = (_ => true), - // Handling special cases where partial function input is not a TilesKey. - specialCase: (View, View, View) => PartialFunction[Any, Any] = ((_, _, _) => Map.empty) -) extends Config((site, here, up) => - scala.Function.unlift((key: Any) => { - val tiles = CoreManager.cores flatMap (core => core.updateWithFilter(up, filterFunc).lift(key)) - if (tiles.size == 0) None else Some(tiles map (tile => tile(properties))) - }).orElse(specialCase(site, here, up)) -) - // A list of all cores. object CoreManager { val cores: List[CoreEntryBase] = List( - // TODO ADD YOUR CORE DEFINITION HERE - new CoreEntry[RocketTileParams, RocketTile](RocketTilesKey, RocketCrossingKey), - new CoreEntry[BoomTileParams, BoomTile](BoomTilesKey, BoomCrossingKey), - new CoreEntry[ArianeTileParams, ArianeTile](ArianeTilesKey, ArianeCrossingKey) + // TODO ADD YOUR CORE DEFINITION HERE; note that the + new CoreEntry[RocketTileParams, RocketTile]("Rocket", RocketTilesKey, RocketCrossingKey), + new CoreEntry[BoomTileParams, BoomTile]("Boom", BoomTilesKey, BoomCrossingKey), + new CoreEntry[ArianeTileParams, ArianeTile]("Ariane", ArianeTilesKey, ArianeCrossingKey) ) } diff --git a/generators/chipyard/src/main/scala/GenericCoreConfig.scala b/generators/chipyard/src/main/scala/GenericCoreConfig.scala new file mode 100644 index 00000000..ac099742 --- /dev/null +++ b/generators/chipyard/src/main/scala/GenericCoreConfig.scala @@ -0,0 +1,133 @@ +package chipyard + +import scala.reflect.ClassTag +import scala.reflect.runtime.universe._ + +import chisel3._ + +import freechips.rocketchip.config.{Parameters, Config, Field, View} +import freechips.rocketchip.subsystem.{SystemBusKey, RocketTilesKey, RocketCrossingParams, RocketCrossingKey} +import freechips.rocketchip.diplomacy.{LazyModule, ClockCrossingType, ValName} +import freechips.rocketchip.diplomaticobjectmodel.logicaltree.LogicalTreeNode +import freechips.rocketchip.rocket._ +import freechips.rocketchip.tile._ + +import boom.common.{BoomTile, BoomTilesKey, BoomCrossingKey, BoomTileParams} +import ariane.{ArianeTile, ArianeTilesKey, ArianeCrossingKey, ArianeTileParams} + +// Extractor object accompanied class +// This is used to check the convertibility for those wrapped in Option, since Option's type is erased at runtime. +trait SubParameterBase { + def toProduct: Product + def cast(p: Any): Any +} +final class SubParameter[T <: Product](param: T) extends SubParameterBase { + def toProduct: Product = param + def cast(p: Any) = p.asInstanceOf[T] +} + +// Extractor object that help identify the parameter case classes. +// Add your customized nested parameter classes (or their commom base classes) here. +object CustomizedSubParameter { + def unapply(param: Product): Option[Product] = param match { + // ADD YOUR NESTED PARAMETER CLASS HERE, in the format shown below in SubParameter + case _ => None + } +} + +// Standard nested +object SubParameter { + def unapply(param: Product): Option[SubParameterBase] = param match { + case p: TileParams => Some(new SubParameter(p)) + case p: CoreParams => Some(new SubParameter(p)) + case p: ICacheParams => Some(new SubParameter(p)) + case p: DCacheParams => Some(new SubParameter(p)) + case p: MulDivParams => Some(new SubParameter(p)) + case p: FPUParams => Some(new SubParameter(p)) + case p: BTBParams => Some(new SubParameter(p)) + case p: BHTParams => Some(new SubParameter(p)) + case CustomizedSubParameter(p) => Some(new SubParameter(p)) + case _ => None + } +} + +// Dynamic update helper for Parameter class. +class CopyParam(paramExtracted: SubParameterBase) { + // Constructor for corresponding TileParams + private val param: Product = paramExtracted.toProduct + private val paramClass = param.getClass + private val paramNames = (paramClass.getDeclaredFields map (f => f.getName)) + private val paramCtor = paramClass.getConstructors.head + + // Function to build value entry + private def buildEntry(value: Any): Any = value match { + case Some(v) => Some(buildEntry(v)) + case SubParameter(p) => new CopyParam(p) + case v => v + } + + // Value of the case class + private val entries = param.productIterator.toList map (v => buildEntry(v)) + + // Update one value entry + private def updateEntry(entry: Any, newValue: Any): Any = entry match { + case Some(e) => newValue match { + case Some(v) => Some(updateEntry(e, v)) + case None => None + } + case e: CopyParam => newValue match { + case newValues: Map[String, Any] => e.update(newValues) + case v => paramExtracted.cast(v) + } + // Use cast() to check the type of the new value. Here I assume that all entries in the parameters class are simple values + // (like Int, BigInt and String), which are all final. This may breaks if a polymorphic type is added (unless it's a case + // class and registered above). + case e => e.getClass.cast(newValue) + } + + // Update the entire parameter object. + def update(newValues: Map[String, Any]): Any = { + val filteredValues = newValues.filter({ case (key, value) => paramNames contains key }) + val newValueList = entries.zipWithIndex map { + case (value, i) if newValues contains paramNames(i) => updateEntry(value, filteredValues(paramNames(i))).asInstanceOf[AnyRef] + case (value, i) => (value match { + case Some(v) => v match { + case copyParam: CopyParam => Some(copyParam.param) + case _ => Some(v) + } + case copyParam: CopyParam => copyParam.param + case _ => value + }).asInstanceOf[AnyRef] + } + paramCtor.newInstance(newValueList:_*) + } + + // For debug purpose - print what's in the object + override def toString(): String = paramClass.getSimpleName + "(" + entries.toString + ")" +} + +object CopyParam { + def apply(param: Product, newValues: Map[String, Any]): Any = param match { + case SubParameter(p) => new CopyParam(p).update(newValues) + case _ => throw new Exception("param is not a known Parameter type: add your custom parameter class to GenericCoreConfig.scala to fix it") + } +} + +// Change parameters for all registered cores in CoreManager. +class GenericCoreConfig ( + // Key-value pairs to be updated (keys are the name of fields). Any field not in a core's parameters will be ignored. + // If a field is a case class containing parameters (or an Option of that), you can use another Map containing the key-value pairs to + // update that case class. Using a new case class instance as the value is also acceptable. + // If a field is an Option, you should wrap your new values with Some() or set it to None. This also applies when a new case + // class instance is used for an Option field. + newValues: Map[String, Any], + // Function for filtering the list of TilesKey. + filterFunc: Any => Boolean = (_ => true), + // Handling special cases where partial function input is not a TilesKey. + specialCase: (View, View, View) => PartialFunction[Any, Any] = ((_, _, _) => Map.empty) +) extends Config((site, here, up) => + scala.Function.unlift((key: Any) => { + val tiles = CoreManager.cores flatMap (core => core.updateWithFilter(up, filterFunc).lift(key)) + if (tiles.size == 0) None else Some(tiles(0)(newValues)) + }).orElse(specialCase(site, here, up)) +) \ No newline at end of file diff --git a/generators/chipyard/src/main/scala/stage/phases/AddDefaultTests.scala b/generators/chipyard/src/main/scala/stage/phases/AddDefaultTests.scala index a36131b1..5855613e 100644 --- a/generators/chipyard/src/main/scala/stage/phases/AddDefaultTests.scala +++ b/generators/chipyard/src/main/scala/stage/phases/AddDefaultTests.scala @@ -33,8 +33,15 @@ 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) - CoreManager.cores map (core => suiteHelper.addGenericTestSuites(core.tileParamsLookup)) + 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 hwacha parameter exists then generate its tests // TODO: find a more elegant way to do this. either through From e021f161dca48ea7b8136208a6c7e1b5c5aff23a Mon Sep 17 00:00:00 2001 From: Zitao Fang Date: Wed, 3 Jun 2020 20:57:31 -0700 Subject: [PATCH 13/42] Remove Debug message --- generators/chipyard/src/main/scala/GenericCoreConfig.scala | 3 --- 1 file changed, 3 deletions(-) diff --git a/generators/chipyard/src/main/scala/GenericCoreConfig.scala b/generators/chipyard/src/main/scala/GenericCoreConfig.scala index ac099742..63bc749f 100644 --- a/generators/chipyard/src/main/scala/GenericCoreConfig.scala +++ b/generators/chipyard/src/main/scala/GenericCoreConfig.scala @@ -101,9 +101,6 @@ class CopyParam(paramExtracted: SubParameterBase) { } paramCtor.newInstance(newValueList:_*) } - - // For debug purpose - print what's in the object - override def toString(): String = paramClass.getSimpleName + "(" + entries.toString + ")" } object CopyParam { From 0f116cb7174bd7baab083975527289c5aa7fed4a Mon Sep 17 00:00:00 2001 From: Zitao Fang Date: Thu, 4 Jun 2020 00:17:05 -0700 Subject: [PATCH 14/42] Tile construction delayed --- generators/chipyard/src/main/scala/CoreManager.scala | 10 ++++++++-- generators/chipyard/src/main/scala/Subsystem.scala | 9 +++++++-- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/generators/chipyard/src/main/scala/CoreManager.scala b/generators/chipyard/src/main/scala/CoreManager.scala index 57b63743..9dc55eff 100644 --- a/generators/chipyard/src/main/scala/CoreManager.scala +++ b/generators/chipyard/src/main/scala/CoreManager.scala @@ -21,7 +21,7 @@ sealed trait CoreEntryBase { def tileParamsLookup(implicit p: Parameters): Seq[TileParams] def updateWithFilter(view: View, p: Any => Boolean): PartialFunction[Any, Map[String, Any] => Any] def instantiateTile(crossingLookup: (Seq[RocketCrossingParams], Int) => Seq[RocketCrossingParams], logicalTreeNode: LogicalTreeNode) - (implicit p: Parameters, valName: ValName): Seq[(TileParams, RocketCrossingParams, BaseTile)] + (implicit p: Parameters, valName: ValName): Seq[(TileParams, RocketCrossingParams, () => BaseTile)] } // Implementation of third-party core entries @@ -53,7 +53,13 @@ class CoreEntry[TileParamsT <: TileParams with Product: TypeTag, TileT <: BaseTi case (param, crossing) => ( param, crossing, - LazyModule(tileCtor.newInstance(param, crossing, PriorityMuxHartIdFromSeq(tileParams), logicalTreeNode, p.asInstanceOf[Parameters]).asInstanceOf[TileT]) + (() => LazyModule(tileCtor.newInstance( + param, + crossing, + PriorityMuxHartIdFromSeq(tileParams), + logicalTreeNode, + p.asInstanceOf[Parameters] + ).asInstanceOf[TileT])) ) } } diff --git a/generators/chipyard/src/main/scala/Subsystem.scala b/generators/chipyard/src/main/scala/Subsystem.scala index 6410ac4e..fa5988e2 100644 --- a/generators/chipyard/src/main/scala/Subsystem.scala +++ b/generators/chipyard/src/main/scala/Subsystem.scala @@ -34,7 +34,9 @@ trait HasChipyardTiles extends HasTiles val module: HasChipyardTilesModuleImp // Generate tiles info from the list of cores in CoreManager - val allTilesInfo: Seq[(TileParams, RocketCrossingParams, BaseTile)] = + // 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))) // Make a tile and wire its nodes into the system, @@ -44,8 +46,11 @@ trait HasChipyardTiles extends HasTiles // This MUST be performed in order of hartid // There is something weird with registering tile-local interrupt controllers to the CLINT. // TODO: investigate why + require((allTilesInfo map (info => info._1.hartId)).max == allTilesInfo.size - 1) val tiles = allTilesInfo.sortWith(_._1.hartId < _._1.hartId).map { - case (param, crossing, tile) => { + case (param, crossing, tileCtor) => { + val tile = tileCtor() + connectMasterPortsToSBus(tile, crossing) connectSlavePortsToCBus(tile, crossing) connectInterrupts(tile, debugOpt, clintOpt, plicOpt) From 98f6f9292eceede4c4e213991487275b58456560 Mon Sep 17 00:00:00 2001 From: Zitao Fang Date: Sat, 6 Jun 2020 16:22:59 -0700 Subject: [PATCH 15/42] Change Generic Config --- .../src/main/scala/ConfigFragments.scala | 21 +- .../chipyard/src/main/scala/CoreManager.scala | 12 +- .../src/main/scala/GenericCoreConfig.scala | 253 +++++++++++------- 3 files changed, 169 insertions(+), 117 deletions(-) diff --git a/generators/chipyard/src/main/scala/ConfigFragments.scala b/generators/chipyard/src/main/scala/ConfigFragments.scala index 4d0e0725..da1372db 100644 --- a/generators/chipyard/src/main/scala/ConfigFragments.scala +++ b/generators/chipyard/src/main/scala/ConfigFragments.scala @@ -13,6 +13,7 @@ import freechips.rocketchip.rocket.{RocketCoreParams, MulDivParams, DCacheParams import freechips.rocketchip.util.{AsyncResetReg} import boom.common.{BoomTilesKey} +import ariane.ArianeTilesKey import testchipip._ import hwacha.{Hwacha} @@ -22,7 +23,8 @@ import sifive.blocks.devices.uart._ import sifive.blocks.devices.spi._ import chipyard.{BuildTop, BuildSystem} -import chipyard.GenericCoreConfig +import chipyard.TilesKey +import chipyard.TileSeq._ /** * TODO: Why do we need this? @@ -59,7 +61,11 @@ class WithSPIFlash(size: BigInt = 0x10000000) extends Config((site, here, up) => SPIFlashParams(rAddress = 0x10040000, fAddress = 0x20000000, fSize = size)) }) -class WithL2TLBs(entries: Int) extends GenericCoreConfig(Map("core" -> Map("nL2TLBEntries" -> entries))) +class WithL2TLBs(entries: Int) extends Config((site, here, up) => { + case TilesKey(tilesKey) => up(tilesKey) tileMap (tile => tile.copy( + core = tile.core.copy(nL2TLBEntries = entries) + )) +}) class WithTracegenSystem extends Config((site, here, up) => { case BuildSystem => (p: Parameters) => LazyModule(new tracegen.TraceGenSystem()(p)) @@ -140,9 +146,8 @@ class WithControlCore extends Config((site, here, up) => { case MaxHartIdBits => log2Up(up(RocketTilesKey, site).size + up(BoomTilesKey, site).size + 1) }) -class WithTraceIO extends GenericCoreConfig( - newValues = Map("trace" -> true), - specialCase = (site, here, up) => { - case TracePortKey => Some(TracePortParams()) - } -) \ No newline at end of file +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()) +}) \ No newline at end of file diff --git a/generators/chipyard/src/main/scala/CoreManager.scala b/generators/chipyard/src/main/scala/CoreManager.scala index 9dc55eff..b5129217 100644 --- a/generators/chipyard/src/main/scala/CoreManager.scala +++ b/generators/chipyard/src/main/scala/CoreManager.scala @@ -18,8 +18,10 @@ import ariane.{ArianeTile, ArianeTilesKey, ArianeCrossingKey, ArianeTileParams} // Base trait for all third-party core entries sealed trait CoreEntryBase { val name: String + + def keyEqual(key: Any): Boolean def tileParamsLookup(implicit p: Parameters): Seq[TileParams] - def updateWithFilter(view: View, p: Any => Boolean): PartialFunction[Any, Map[String, Any] => Any] + def instantiateTile(crossingLookup: (Seq[RocketCrossingParams], Int) => Seq[RocketCrossingParams], logicalTreeNode: LogicalTreeNode) (implicit p: Parameters, valName: ValName): Seq[(TileParams, RocketCrossingParams, () => BaseTile)] } @@ -35,15 +37,11 @@ class CoreEntry[TileParamsT <: TileParams with Product: TypeTag, TileT <: BaseTi private val tileClass = mirror.runtimeClass(typeOf[TileT].typeSymbol.asClass) private val tileCtor = tileClass.getConstructors.filter(ctor => ctor.getParameterTypes()(4) == classOf[Parameters]).head + def keyEqual(key: Any) = key == tilesKey + // Tile parameter lookup using correct type def tileParamsLookup(implicit p: Parameters) = p(tilesKey) - // If this core meet the requirement given by p, update parameter fields in the map - def updateWithFilter(view: View, p: Any => Boolean): PartialFunction[Any, Map[String, Any] => Any] = { - case key if (key == tilesKey && p(tilesKey)) => newValues => view(tilesKey) map - (tile => CopyParam(tile, newValues)) - } - // 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) = { diff --git a/generators/chipyard/src/main/scala/GenericCoreConfig.scala b/generators/chipyard/src/main/scala/GenericCoreConfig.scala index 63bc749f..159b8b69 100644 --- a/generators/chipyard/src/main/scala/GenericCoreConfig.scala +++ b/generators/chipyard/src/main/scala/GenericCoreConfig.scala @@ -15,116 +15,165 @@ import freechips.rocketchip.tile._ import boom.common.{BoomTile, BoomTilesKey, BoomCrossingKey, BoomTileParams} import ariane.{ArianeTile, ArianeTilesKey, ArianeCrossingKey, ArianeTileParams} -// Extractor object accompanied class -// This is used to check the convertibility for those wrapped in Option, since Option's type is erased at runtime. -trait SubParameterBase { - def toProduct: Product - def cast(p: Any): Any -} -final class SubParameter[T <: Product](param: T) extends SubParameterBase { - def toProduct: Product = param - def cast(p: Any) = p.asInstanceOf[T] +// 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( + val bootFreqHz: BigInt, + val useVM: Boolean, + val useUser: Boolean, + val useSupervisor: Boolean, + val useDebug: Boolean, + val useAtomics: Boolean, + val useAtomicsOnlyForIO: Boolean, + val useCompressed: Boolean, + override val useVector: Boolean, + val useSCIE: Boolean, + val useRVE: Boolean, + val mulDiv: Option[MulDivParams], + val fpu: Option[FPUParams], + val fetchWidth: Int, + val decodeWidth: Int, + val retireWidth: Int, + val instBits: Int, + val nLocalInterrupts: Int, + val nPMPs: Int, + val pmpGranularity: Int, + val nBreakpoints: Int, + val useBPWatch: Boolean, + val nPerfCounters: Int, + val haveBasicCounters: Boolean, + val haveFSDirty: Boolean, + val misaWritable: Boolean, + val haveCFlush: Boolean, + val nL2TLBEntries: Int, + val mtvecInit: Option[BigInt], + val mtvecWritable: Boolean, + // The original object + val _origin: CoreParams +) extends CoreParams { + def this(coreParams: CoreParams) = this( + bootFreqHz = coreParams.bootFreqHz, + useVM = coreParams.useVM, + useUser = coreParams.useUser, + useSupervisor = coreParams.useSupervisor, + useDebug = coreParams.useDebug, + useAtomics = coreParams.useAtomics, + useAtomicsOnlyForIO = coreParams.useAtomicsOnlyForIO, + useCompressed = coreParams.useCompressed, + useVector = coreParams.useVector, + useSCIE = coreParams.useSCIE, + useRVE = coreParams.useRVE, + mulDiv = coreParams.mulDiv, + fpu = coreParams.fpu, + fetchWidth = coreParams.fetchWidth, + decodeWidth = coreParams.decodeWidth, + retireWidth = coreParams.retireWidth, + instBits = coreParams.instBits, + nLocalInterrupts = coreParams.nLocalInterrupts, + nPMPs = coreParams.nPMPs, + pmpGranularity = coreParams.pmpGranularity, + nBreakpoints = coreParams.nBreakpoints, + useBPWatch = coreParams.useBPWatch, + nPerfCounters = coreParams.nPerfCounters, + haveBasicCounters = coreParams.haveBasicCounters, + haveFSDirty = coreParams.haveFSDirty, + misaWritable = coreParams.misaWritable, + haveCFlush = coreParams.haveCFlush, + nL2TLBEntries = coreParams.nL2TLBEntries, + mtvecInit = coreParams.mtvecInit, + mtvecWritable = coreParams.mtvecWritable, + + _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 } -// Extractor object that help identify the parameter case classes. -// Add your customized nested parameter classes (or their commom base classes) here. -object CustomizedSubParameter { - def unapply(param: Product): Option[Product] = param match { - // ADD YOUR NESTED PARAMETER CLASS HERE, in the format shown below in SubParameter - case _ => None +case class GenericTileParams( + val core: GenericCoreParams, + val icache: Option[ICacheParams], + val dcache: Option[DCacheParams], + val btb: Option[BTBParams], + val hartId: Int, + val beuAddr: Option[BigInt], + val blockerCtrlAddr: Option[BigInt], + val name: Option[String], + // The original object + val _origin: TileParams +) extends TileParams { + // Copy constructor to build the params + def this(tileParams: TileParams) = this( + core = new GenericCoreParams(tileParams.core), + icache = tileParams.icache, + dcache = tileParams.dcache, + btb = tileParams.btb, + hartId = tileParams.hartId, + beuAddr = tileParams.beuAddr, + blockerCtrlAddr = tileParams.blockerCtrlAddr, + name = tileParams.name, + + _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] } } -// Standard nested -object SubParameter { - def unapply(param: Product): Option[SubParameterBase] = param match { - case p: TileParams => Some(new SubParameter(p)) - case p: CoreParams => Some(new SubParameter(p)) - case p: ICacheParams => Some(new SubParameter(p)) - case p: DCacheParams => Some(new SubParameter(p)) - case p: MulDivParams => Some(new SubParameter(p)) - case p: FPUParams => Some(new SubParameter(p)) - case p: BTBParams => Some(new SubParameter(p)) - case p: BHTParams => Some(new SubParameter(p)) - case CustomizedSubParameter(p) => Some(new SubParameter(p)) - case _ => None - } +// 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 } -// Dynamic update helper for Parameter class. -class CopyParam(paramExtracted: SubParameterBase) { - // Constructor for corresponding TileParams - private val param: Product = paramExtracted.toProduct - private val paramClass = param.getClass - private val paramNames = (paramClass.getDeclaredFields map (f => f.getName)) - private val paramCtor = paramClass.getConstructors.head +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]] - // Function to build value entry - private def buildEntry(value: Any): Any = value match { - case Some(v) => Some(buildEntry(v)) - case SubParameter(p) => new CopyParam(p) - case v => v - } - - // Value of the case class - private val entries = param.productIterator.toList map (v => buildEntry(v)) - - // Update one value entry - private def updateEntry(entry: Any, newValue: Any): Any = entry match { - case Some(e) => newValue match { - case Some(v) => Some(updateEntry(e, v)) - case None => None - } - case e: CopyParam => newValue match { - case newValues: Map[String, Any] => e.update(newValues) - case v => paramExtracted.cast(v) - } - // Use cast() to check the type of the new value. Here I assume that all entries in the parameters class are simple values - // (like Int, BigInt and String), which are all final. This may breaks if a polymorphic type is added (unless it's a case - // class and registered above). - case e => e.getClass.cast(newValue) - } - - // Update the entire parameter object. - def update(newValues: Map[String, Any]): Any = { - val filteredValues = newValues.filter({ case (key, value) => paramNames contains key }) - val newValueList = entries.zipWithIndex map { - case (value, i) if newValues contains paramNames(i) => updateEntry(value, filteredValues(paramNames(i))).asInstanceOf[AnyRef] - case (value, i) => (value match { - case Some(v) => v match { - case copyParam: CopyParam => Some(copyParam.param) - case _ => Some(v) - } - case copyParam: CopyParam => copyParam.param - case _ => value - }).asInstanceOf[AnyRef] - } - paramCtor.newInstance(newValueList:_*) + tileList map (tileParams => f(new GenericTileParams(tileParams)).convert) } } - -object CopyParam { - def apply(param: Product, newValues: Map[String, Any]): Any = param match { - case SubParameter(p) => new CopyParam(p).update(newValues) - case _ => throw new Exception("param is not a known Parameter type: add your custom parameter class to GenericCoreConfig.scala to fix it") - } +object TileSeq { + implicit def convertSeq(s: Seq[Any]) = new TileSeq(s) } - -// Change parameters for all registered cores in CoreManager. -class GenericCoreConfig ( - // Key-value pairs to be updated (keys are the name of fields). Any field not in a core's parameters will be ignored. - // If a field is a case class containing parameters (or an Option of that), you can use another Map containing the key-value pairs to - // update that case class. Using a new case class instance as the value is also acceptable. - // If a field is an Option, you should wrap your new values with Some() or set it to None. This also applies when a new case - // class instance is used for an Option field. - newValues: Map[String, Any], - // Function for filtering the list of TilesKey. - filterFunc: Any => Boolean = (_ => true), - // Handling special cases where partial function input is not a TilesKey. - specialCase: (View, View, View) => PartialFunction[Any, Any] = ((_, _, _) => Map.empty) -) extends Config((site, here, up) => - scala.Function.unlift((key: Any) => { - val tiles = CoreManager.cores flatMap (core => core.updateWithFilter(up, filterFunc).lift(key)) - if (tiles.size == 0) None else Some(tiles(0)(newValues)) - }).orElse(specialCase(site, here, up)) -) \ No newline at end of file From 119a44b1219a6930bcf895d91cd9b7f7d0867f7f Mon Sep 17 00:00:00 2001 From: Zitao Fang Date: Sat, 13 Jun 2020 01:36:14 -0700 Subject: [PATCH 16/42] Use config to manage core registration and custom tests --- .../src/main/scala/ConfigFragments.scala | 9 +- .../chipyard/src/main/scala/CoreManager.scala | 53 +++++++++- ...reConfig.scala => GenericCoreParams.scala} | 97 +++++++------------ .../chipyard/src/main/scala/Subsystem.scala | 2 +- .../chipyard/src/main/scala/TestSuites.scala | 15 +++ .../scala/stage/phases/AddDefaultTests.scala | 16 ++- 6 files changed, 111 insertions(+), 81 deletions(-) rename generators/chipyard/src/main/scala/{GenericCoreConfig.scala => GenericCoreParams.scala} (69%) diff --git a/generators/chipyard/src/main/scala/ConfigFragments.scala b/generators/chipyard/src/main/scala/ConfigFragments.scala index da1372db..8336bdc5 100644 --- a/generators/chipyard/src/main/scala/ConfigFragments.scala +++ b/generators/chipyard/src/main/scala/ConfigFragments.scala @@ -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()) -}) \ No newline at end of file +}) diff --git a/generators/chipyard/src/main/scala/CoreManager.scala b/generators/chipyard/src/main/scala/CoreManager.scala index b5129217..d013cc7c 100644 --- a/generators/chipyard/src/main/scala/CoreManager.scala +++ b/generators/chipyard/src/main/scala/CoreManager.scala @@ -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 } diff --git a/generators/chipyard/src/main/scala/GenericCoreConfig.scala b/generators/chipyard/src/main/scala/GenericCoreParams.scala similarity index 69% rename from generators/chipyard/src/main/scala/GenericCoreConfig.scala rename to generators/chipyard/src/main/scala/GenericCoreParams.scala index 159b8b69..28db42b1 100644 --- a/generators/chipyard/src/main/scala/GenericCoreConfig.scala +++ b/generators/chipyard/src/main/scala/GenericCoreParams.scala @@ -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) } diff --git a/generators/chipyard/src/main/scala/Subsystem.scala b/generators/chipyard/src/main/scala/Subsystem.scala index fa5988e2..4ac92c4e 100644 --- a/generators/chipyard/src/main/scala/Subsystem.scala +++ b/generators/chipyard/src/main/scala/Subsystem.scala @@ -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. diff --git a/generators/chipyard/src/main/scala/TestSuites.scala b/generators/chipyard/src/main/scala/TestSuites.scala index 2261000f..5a929010 100644 --- a/generators/chipyard/src/main/scala/TestSuites.scala +++ b/generators/chipyard/src/main/scala/TestSuites.scala @@ -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 +}) diff --git a/generators/chipyard/src/main/scala/stage/phases/AddDefaultTests.scala b/generators/chipyard/src/main/scala/stage/phases/AddDefaultTests.scala index 5855613e..b170706e 100644 --- a/generators/chipyard/src/main/scala/stage/phases/AddDefaultTests.scala +++ b/generators/chipyard/src/main/scala/stage/phases/AddDefaultTests.scala @@ -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 From c5c272b90dbc3532de5429056cd43c30dc28c25c Mon Sep 17 00:00:00 2001 From: Zitao Fang Date: Fri, 19 Jun 2020 13:51:57 -0700 Subject: [PATCH 17/42] Custom core doc first draft --- docs/Customization/Custom-Core.rst | 286 ++++++++++++++++++++++ docs/Customization/Heterogeneous-SoCs.rst | 2 + docs/Customization/index.rst | 2 + 3 files changed, 290 insertions(+) create mode 100644 docs/Customization/Custom-Core.rst diff --git a/docs/Customization/Custom-Core.rst b/docs/Customization/Custom-Core.rst new file mode 100644 index 00000000..bffdc236 --- /dev/null +++ b/docs/Customization/Custom-Core.rst @@ -0,0 +1,286 @@ +.. _custom_core: + +Adding a custom core +==================== + +You may want to add a custom RISC-V core to Chipyard generator. If the top module of your core is not in Chisel, +you will first need to create a Verilog blackbox for it. See ::ref:`_incorporating-verilog-blocks` for instructions. +Once you have a top module in Chisel, you are ready to create integrate it with Chipyard. + +.. note:: + + RoCC is not supported by custom core currently. Please use Rocket or Boom if you need to use RoCC. + +.. note:: + + Custom core doesn't support FireSim at this time. + +Parameter Case Classes +---------------------- + +Chipyard will generate a core for every ``TileParams`` object it discovered in the current config. +``TileParams`` is a trait containing the information needed to create a tile, and every custom core must implement +their own version of ``TileParams``, as well as ``CoreParams`` which is passed as a field in ``TileParams``. + +``TileParams`` holds the parameters that are the same for every generated core, while ``CoreParams`` contains those +that can vary from cores to cores. They must be implemented as case classes with fields that can be overridden by +other config fragments as the constructor parameters. See the appendix at the bottom of the page for a list of +variable to be implemented. You can also add custom fields to them, but standard fields should always be preferred. + +Now you have your parameter classes, you will need config keys to hold them. There are two required keys: + +.. code-block:: scala + + case object MyTilesKey extends Field[Seq[MyTileParams]](Nil) + case object MyCrossingKey extends Field[Seq[RocketCrossingParams]](List(RocketCrossingParams())) + +``MyCrossingKey`` here is used to store information about the clock-crossing behavior of the core, and it is normally +set to its default values. + +``TileParams`` and ``CoreParams`` contains the following fields: + +.. code-block:: scala + + trait TileParams { + val core: CoreParams // Core parameters (see below) + val icache: Option[ICacheParams] // Not used if you use your own I1 cache + val dcache: Option[DCacheParams] // Not used if you use your own D1 cache + val btb: Option[BTBParams] // Not used if you use your own BTB / branch predictor + val hartId: Int // Hart ID: Must be unique within a design config + val beuAddr: Option[BigInt] + val blockerCtrlAddr: Option[BigInt] + val name: Option[String] // Name of the core + } + + trait CoreParams { + val bootFreqHz: BigInt // Frequency + val useVM: Boolean // Support virtual memory + val useUser: Boolean // Support user mode + val useSupervisor: Boolean // Support supervisor mode + val useDebug: Boolean // Support RISC-V debug specs + val useAtomics: Boolean // Support A extension + val useAtomicsOnlyForIO: Boolean // Support A extension for memory-mapped IO (may be true even if useAtomics is false) + val useCompressed: Boolean // Support C extension + val useVector: Boolean = false // Support V extension + val useSCIE: Boolean + val useRVE: Boolean + val mulDiv: Option[MulDivParams] // M extension and related setting (Only used by Rocket core, simply use its default value) + val fpu: Option[FPUParams] // F and D extensions and related setting (see below) + val fetchWidth: Int // Max # of insts fetched every cycle + val decodeWidth: Int // Max # of insts decoded every cycle + val retireWidth: Int // Max # of insts retired every cycle + val instBits: Int // Instruction bits (if 32 bit and 64 bit are both supported, use 64) + val nLocalInterrupts: Int // # of local interrupts (see SiFive interrupt cookbook) + val nPMPs: Int // # of Physical Memory Protection units + val pmpGranularity: Int // Size of the smallest unit of region for PMP unit (must be power of 2) + val nBreakpoints: Int // # of breakpoints supported (in RISC-V debug specs) + val useBPWatch: Boolean + val nPerfCounters: Int // # of supported performance counters + val haveBasicCounters: Boolean // Support basic counters defined in the RISC-V counter extension + val haveFSDirty: Boolean + val misaWritable: Boolean // Support writable misa CSR (like variable instruction bits) + val haveCFlush: Boolean + val nL2TLBEntries: Int // # of L2 TLB entries + val mtvecInit: Option[BigInt] // mtvec CSR (of V extension) initial value + val mtvecWritable: Boolean // If mtvec CSR is writable + + // Normally, you don't need to change these values (except lrscCycles) + def customCSRs(implicit p: Parameters): CustomCSRs = new CustomCSRs + + def hasSupervisorMode: Boolean = useSupervisor || useVM + def instBytes: Int = instBits / 8 + def fetchBytes: Int = fetchWidth * instBytes + // This field is used only with the D1 cache of Rocket chip. Simply set it to the default value 80. + def lrscCycles: Int + + def dcacheReqTagBits: Int = 6 + + def minFLen: Int = 32 + def vLen: Int = 0 + def sLen: Int = 0 + def eLen(xLen: Int, fLen: Int): Int = xLen max fLen + def vMemDataBits: Int = 0 + } + + case class FPUParams( + minFLen: Int = 32, // Minimum floating point length (no need to change) + fLen: Int = 64, // Maximum floating point length, use 32 if only single precision is supported + divSqrt: Boolean = true, // Div/Sqrt operation supported + sfmaLatency: Int = 3, // + dfmaLatency: Int = 4 + ) + +Most of the fields here are originally designed for Rocket core and contains some architecture-specific details, but +many of them are general enough to be useful for other cores. It is strongly recommended to use these fields instead +of creating your own custom fields when applicable. + +Tile Class +---------- + +In Chipyard, all connections with other components on SoC are defined a core's `Tile` class, while the implementation +of the actual hardware are in the implementation class. This structure allows Chipyard to use the Diplomacy framework +to resolve paramters and connections before elaboration. + +All tile classes implement ``BaseTile`` and will normally implement ``SinksExternalInterrupts`` and ``SourcesExternalNotifications``, +which allow the tile to accept external interrupt. A typical tile has the following form: + +.. code-block:: scala + + class MyTile( + val myParams: MyTileParams, + crossing: ClockCrossingType, + lookup: LookupByHartIdImpl, + q: Parameters, + logicalTreeNode: LogicalTreeNode) + extends BaseTile(myParams, crossing, lookup, q) + with SinksExternalInterrupts + with SourcesExternalNotifications + { + + // Private constructor ensures altered LazyModule.p is used implicitly + def this(params: MyTileParams, crossing: RocketCrossingParams, lookup: LookupByHartIdImpl, logicalTreeNode: LogicalTreeNode)(implicit p: Parameters) = + this(params, crossing.crossingType, lookup, p, logicalTreeNode) + + // Require TileLink nodes + val intOutwardNode = IntIdentityNode() + val masterNode = visibilityNode + val slaveNode = TLIdentityNode() + + // Implementation class (See below) + override lazy val module = new MyTileModuleImp(this) + + // Required entry of CPU device in the device tree for interrupt purpose + val cpuDevice: SimpleDevice = new SimpleDevice("cpu", Seq("my-organization,my-cpu", "riscv")) { + override def parent = Some(ResourceAnchors.cpus) + override def describe(resources: ResourceBindings): Description = { + val Description(name, mapping) = super.describe(resources) + Description(name, mapping ++ + cpuProperties ++ + nextLevelCacheProperty ++ + tileProperties) + } + } + + ResourceBinding { + Resource(cpuDevice, "reg").bind(ResourceAddress(hartId)) + } + + // (Connection to bus, interrupt, etc.) + } + +TileLink Connection +------------------- + +Chipyard use TileLink as its onboard bus protocol, and if your core doesn't use TileLink, you will need to convert them +in the tile class. Below is an example of how to connect a core using AXI4 to the TileLink bus: + +.. code-block:: scala + + val memoryTap = TLIdentityNode() // Every bus connection should have their own tap node + (tlMasterXbar.node // tlMasterXbar is the bus crossbar to be used when this core / tile is acting as a master; otherwise, use tlSlaveXBar + := memoryTap + := TLBuffer() + := TLFIFOFixer(TLFIFOFixer.all) // fix FIFO ordering + := TLWidthWidget(beatBytes) // reduce size of TL + := AXI4ToTL() // convert to TL + := AXI4UserYanker(Some(2)) // remove user field on AXI interface. need but in reality user intf. not needed + := AXI4Fragmenter() // deal with multi-beat xacts + := memAXI4Node) // The custom node, see below + +Remember, you may not need all of these intermediate widgets. See :::ref:`Diplomatic-Widgets` for the meaning of each intermediate +widget. If you are using TileLink, then you only need the tap node and the TileLink node used by your components. Also, Chipyard +support AHB, APB and AXIS, and most of the AXI4 widgets has equivalent widget for these bus protocol. See the reference page for +more info. + +``memAXI4Node`` is an AXI4 master node and is defined as following in our example: + +.. code-block:: scala + + val memAXI4Node = AXI4MasterNode( + Seq(AXI4MasterPortParameters( + masters = Seq(AXI4MasterParameters( + name = portName, + id = IdRange(0, 1 << idBits)))))) + +where ``portName`` and ``idBits`` are the parameter provides by the tile. Make sure to read :::ref:`node-tyoes` to check out what +type of nodes Chipyard supports and their parameters! + +Also, by default, there are boundary buffers for both master and slave connections to the bus when they are leaving the tile, and you +can override the following two functions to control how to buffer the bus requests/responses: + +.. code-block:: scala + + protected def makeMasterBoundaryBuffers(implicit p: Parameters): TLBuffer + protected def makeSlaveBoundaryBuffers(implicit p: Parameters): TLBuffer + +Interrupt +--------- + +Chipyard allows a tile to either receive interrupts from other devices or initiate interrupts to notify other cores/devices. +In the tile that inherited ``SinksExternalInterrupts``, one can create a ``TileInterrupts`` object (a Chisel bundle) and +call ``decodeCoreInterrupts`` with the object as the argument. You can then read the interrupt bits from the object. +The definition of ``TileInterrupts`` is + +.. code-block:: scala + + class TileInterrupts(implicit p: Parameters) extends CoreBundle()(p) { + val debug = Bool() // debug interrupt + val mtip = Bool() // Machine level timer interrupt + val msip = Bool() // Machine level software interrupt + val meip = Bool() // Machine level external interrupt + val seip = usingSupervisor.option(Bool()) // Valid only if supervisor mode is supported + val lip = Vec(coreParams.nLocalInterrupts, Bool()) // Local interrupts + } + +This function should be in the implementation class since it involves hardware generation. +Also, the tile can also notify other cores or devices for some events by calling following functions (in implementation class): + +.. code-block:: scala + + def reportHalt(could_halt: Option[Bool]) // Triggered when there is an unrecoverable hardware error (halt the machine) + def reportHalt(errors: Seq[CanHaveErrors]) // Varient for standard error bundle (used only by cache when there's an ECC error) + reportCease(could_cease: Option[Bool], quiescenceCycles: Int = 8) // Triggered when the core stop retiring instructions (like clock gating) + reportWFI(could_wfi: Option[Bool]) // Triggered when a WFI instruciton is executed + +Implementation Class +-------------------- + +The implementation class is of the following form: + +.. code-block:: scala + + class MyTileModuleImp(outer: MyTile) extends BaseTileModuleImp(outer){ + // annotate the parameters + Annotated.params(this, outer.tileParams) + + // TODO: Create the top module of the core and connect it with the ports in "outer" + } + +In the body of this class, you can look up any parameters by calling ``p({key})``, where ``{key}`` is the config key of +the value you want to look up. For a list of available keys, see the appendix below. + +If you create an AXI4 node (or equivalents), you will need to connect them to your core. + +Integrate the Core +------------------ + +To use your core in a set of config, you would need a config fragment that would create a ``TileParams`` object of your core in +the current config. An example of such config will be like this: + +.. code-block:: scala + + class WithNMyCores(n: Int) extends Config( + new RegisterCore(new CoreEntry[MyTileParams, MyTile]("MyCore", MyTilesKey, MyCrossingKey)) ++ + new Config((site, here, up) => { + case MyTilesKey => { + List.tabulate(n)(i => MyTileParams(hartId = i)) + } + }) + ) + +Where ``RegisterCore`` will register the core with chipyard so that it can be recognized by generic config. This is required for +all custom cores. You can also create other config fragments to change other parameters. + +Now you have finished all the steps to prepare your cores for Chipyard! To generate the custom core, simply follow the instructions +in :::ref:`_custom_chisel` to add your project to the build system, then create a config by following the steps in :::ref:`_hetero_socs_`. +You can now run any desired workflow for the new config just as you do for the built-in cores. diff --git a/docs/Customization/Heterogeneous-SoCs.rst b/docs/Customization/Heterogeneous-SoCs.rst index c640e31c..204b3159 100644 --- a/docs/Customization/Heterogeneous-SoCs.rst +++ b/docs/Customization/Heterogeneous-SoCs.rst @@ -1,3 +1,5 @@ +.. _hetero_socs_: + Heterogeneous SoCs =============================== diff --git a/docs/Customization/index.rst b/docs/Customization/index.rst index 9421b79a..38fdf622 100644 --- a/docs/Customization/index.rst +++ b/docs/Customization/index.rst @@ -7,6 +7,8 @@ These guides will walk you through customization of your system-on-chip: - How to include your custom Chisel sources in the Chipyard build system +- Adding custom core + - Adding custom RoCC accelerators to an existing Chipyard core (BOOM or Rocket) - Adding custom MMIO widgets to the Chipyard memory system by Tilelink or AXI4, with custom Top-level IOs From c407e39cd8c9a4a8dd2e2f19138174cc4cd6dffb Mon Sep 17 00:00:00 2001 From: Zitao Fang Date: Sat, 20 Jun 2020 01:04:56 -0700 Subject: [PATCH 18/42] Completed most documentation (without AXI4 bus) --- docs/Customization/Custom-Core.rst | 78 ++++++++++++++++++++++-------- 1 file changed, 57 insertions(+), 21 deletions(-) diff --git a/docs/Customization/Custom-Core.rst b/docs/Customization/Custom-Core.rst index bffdc236..5a5cc627 100644 --- a/docs/Customization/Custom-Core.rst +++ b/docs/Customization/Custom-Core.rst @@ -11,10 +11,6 @@ Once you have a top module in Chisel, you are ready to create integrate it with RoCC is not supported by custom core currently. Please use Rocket or Boom if you need to use RoCC. -.. note:: - - Custom core doesn't support FireSim at this time. - Parameter Case Classes ---------------------- @@ -37,18 +33,19 @@ Now you have your parameter classes, you will need config keys to hold them. The ``MyCrossingKey`` here is used to store information about the clock-crossing behavior of the core, and it is normally set to its default values. -``TileParams`` and ``CoreParams`` contains the following fields: +``TileParams`` and ``CoreParams`` contains the following fields (you may ignore any fields marked "Rocket specific" and +use their default values, although it is recommended to use them if you need a custom field with similar purposes) : .. code-block:: scala trait TileParams { val core: CoreParams // Core parameters (see below) - val icache: Option[ICacheParams] // Not used if you use your own I1 cache - val dcache: Option[DCacheParams] // Not used if you use your own D1 cache - val btb: Option[BTBParams] // Not used if you use your own BTB / branch predictor + val icache: Option[ICacheParams] // Rocket specific: I1 cache option + val dcache: Option[DCacheParams] // Rocket specific: D1 cache option + val btb: Option[BTBParams] // Rocket specific: BTB / branch predictor option val hartId: Int // Hart ID: Must be unique within a design config - val beuAddr: Option[BigInt] - val blockerCtrlAddr: Option[BigInt] + val beuAddr: Option[BigInt] // Rocket specific: Bus Error Unit for Rocket Core + val blockerCtrlAddr: Option[BigInt] // Rocket specific: Bus Blocker for Rocket Core val name: Option[String] // Name of the core } @@ -62,9 +59,9 @@ set to its default values. val useAtomicsOnlyForIO: Boolean // Support A extension for memory-mapped IO (may be true even if useAtomics is false) val useCompressed: Boolean // Support C extension val useVector: Boolean = false // Support V extension - val useSCIE: Boolean - val useRVE: Boolean - val mulDiv: Option[MulDivParams] // M extension and related setting (Only used by Rocket core, simply use its default value) + val useSCIE: Boolean // Support custom instructions (in custom-0 and custom-1) + val useRVE: Boolean // Use E base ISA + val mulDiv: Option[MulDivParams] // *Rocket specific: M extension related setting (Use Some(MulDivParams()) to indicate M extension supported) val fpu: Option[FPUParams] // F and D extensions and related setting (see below) val fetchWidth: Int // Max # of insts fetched every cycle val decodeWidth: Int // Max # of insts decoded every cycle @@ -73,13 +70,13 @@ set to its default values. val nLocalInterrupts: Int // # of local interrupts (see SiFive interrupt cookbook) val nPMPs: Int // # of Physical Memory Protection units val pmpGranularity: Int // Size of the smallest unit of region for PMP unit (must be power of 2) - val nBreakpoints: Int // # of breakpoints supported (in RISC-V debug specs) - val useBPWatch: Boolean + val nBreakpoints: Int // # of hardware breakpoints supported (in RISC-V debug specs) + val useBPWatch: Boolean // Support hardware breakpoints val nPerfCounters: Int // # of supported performance counters val haveBasicCounters: Boolean // Support basic counters defined in the RISC-V counter extension - val haveFSDirty: Boolean + val haveFSDirty: Boolean // If true, the core will set FS field in mstatus CSR to dirty when appropriate val misaWritable: Boolean // Support writable misa CSR (like variable instruction bits) - val haveCFlush: Boolean + val haveCFlush: Boolean // Rocket specific: enables Rocket's custom instruction extension to flush the cache val nL2TLBEntries: Int // # of L2 TLB entries val mtvecInit: Option[BigInt] // mtvec CSR (of V extension) initial value val mtvecWritable: Boolean // If mtvec CSR is writable @@ -90,7 +87,7 @@ set to its default values. def hasSupervisorMode: Boolean = useSupervisor || useVM def instBytes: Int = instBits / 8 def fetchBytes: Int = fetchWidth * instBytes - // This field is used only with the D1 cache of Rocket chip. Simply set it to the default value 80. + // Rocket specific: Longest possible latency of Rocket core D1 cache. Simply set it to the default value 80. def lrscCycles: Int def dcacheReqTagBits: Int = 6 @@ -106,8 +103,8 @@ set to its default values. minFLen: Int = 32, // Minimum floating point length (no need to change) fLen: Int = 64, // Maximum floating point length, use 32 if only single precision is supported divSqrt: Boolean = true, // Div/Sqrt operation supported - sfmaLatency: Int = 3, // - dfmaLatency: Int = 4 + sfmaLatency: Int = 3, // Rocket specific: Fused multiply-add pipeline latency (single precision) + dfmaLatency: Int = 4 // Rocket specific: Fused multiply-add pipeline latency (double precision) ) Most of the fields here are originally designed for Rocket core and contains some architecture-specific details, but @@ -213,6 +210,8 @@ can override the following two functions to control how to buffer the bus reques protected def makeMasterBoundaryBuffers(implicit p: Parameters): TLBuffer protected def makeSlaveBoundaryBuffers(implicit p: Parameters): TLBuffer +You can find more information on ``TLBuffer`` in :::ref:`Diplomatic-Widgets`. + Interrupt --------- @@ -240,7 +239,40 @@ Also, the tile can also notify other cores or devices for some events by calling def reportHalt(could_halt: Option[Bool]) // Triggered when there is an unrecoverable hardware error (halt the machine) def reportHalt(errors: Seq[CanHaveErrors]) // Varient for standard error bundle (used only by cache when there's an ECC error) reportCease(could_cease: Option[Bool], quiescenceCycles: Int = 8) // Triggered when the core stop retiring instructions (like clock gating) - reportWFI(could_wfi: Option[Bool]) // Triggered when a WFI instruciton is executed + reportWFI(could_wfi: Option[Bool]) // Triggered when a WFI instruction is executed + +Trace (Optional) +---------------- + +Chipyard provides a set of ports for instruction trace that conforms with related RISC-V standard. +If you are using FireSim, it is recommended to implement these trace ports to enable FireSim to read trace. + +There are one inbound node ``traceAuxSinkNode.bundle: TraceAux`` and two outbound nodes ``traceCoreSourceNode.bundle: TraceCoreInterface`` +and ``bpwatchSourceNode.bundle: Vec[BPWatch]``. Note that the length of ``bpwatchSourceNode`` is equal to the max number of +breakpoints (set by ``nBreakpoints`` in ``CoreParams``). Below is the definition of these types: + +.. code-block:: scala + + // Control signal from the external tracer + class TraceAux extends Bundle { + val enable = Bool() // Enable trace output + val stall = Bool() // If true, the core should stall + } + // Check RISC-V Processor Trace spec V1.0 for more information of this interface + class TraceCoreInterface (val params: TraceCoreParams) extends Bundle { + val group = Vec(params.nGroups, new TraceCoreGroup(params)) + val priv = UInt(4.W) + val tval = UInt(params.xlen.W) + val cause = UInt(params.xlen.W) + } + // Address Breakpoint and watchpoint info (n is the retire width) + class BPWatch (val n: Int) extends Bundle() { + val valid = Vec(n, Bool()) // Valid bit of the output + val rvalid = Vec(n, Bool()) // Break on read + val wvalid = Vec(n, Bool()) // Break on write + val ivalid = Vec(n, Bool()) // Break on execute + val action = UInt(3.W) // Exception code (3 usually) + } Implementation Class -------------------- @@ -261,6 +293,10 @@ the value you want to look up. For a list of available keys, see the appendix be If you create an AXI4 node (or equivalents), you will need to connect them to your core. +.. warning:: + + TODO: Documenting bus connection + Integrate the Core ------------------ From 486cc5fce14c69c07cc55145fafc5c4c7d1d7a8c Mon Sep 17 00:00:00 2001 From: David Biancolin Date: Sat, 20 Jun 2020 13:57:11 -0700 Subject: [PATCH 19/42] [firechip] Add a small target that should fit on all hosts --- .../firechip/src/main/scala/TargetConfigs.scala | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/generators/firechip/src/main/scala/TargetConfigs.scala b/generators/firechip/src/main/scala/TargetConfigs.scala index 63b4d2fe..830188f3 100644 --- a/generators/firechip/src/main/scala/TargetConfigs.scala +++ b/generators/firechip/src/main/scala/TargetConfigs.scala @@ -125,6 +125,20 @@ class FireSimQuadRocketConfig extends Config( new WithFireSimConfigTweaks ++ new chipyard.QuadRocketConfig) +// Should fit on all supported hosts +class FireSimSmallSystemConfig extends Config( + new WithDefaultFireSimBridges ++ + new WithDefaultMemModel ++ + new WithBootROM ++ + new WithPeripheryBusFrequency(BigInt(3200000000L)) ++ + new WithoutClockGating ++ + new WithoutTLMonitors ++ + new freechips.rocketchip.subsystem.WithExtMemSize(1 << 28) ++ + new testchipip.WithTSI ++ + new testchipip.WithBlockDevice ++ + new chipyard.config.WithUART ++ + new freechips.rocketchip.subsystem.WithInclusiveCache(nWays = 2, capacityKB = 64) ++ + new chipyard.RocketConfig) //***************************************************************** // Boom config, base off chipyard's LargeBoomConfig From 34bc8da0024df1957d7a760d0ac23ed0d8a31874 Mon Sep 17 00:00:00 2001 From: Zitao Fang Date: Mon, 22 Jun 2020 17:57:17 -0700 Subject: [PATCH 20/42] Add a list of common config keys --- docs/Customization/Custom-Core.rst | 98 ++++++++++++++++++++++++++++-- 1 file changed, 93 insertions(+), 5 deletions(-) diff --git a/docs/Customization/Custom-Core.rst b/docs/Customization/Custom-Core.rst index 5a5cc627..6d0a9956 100644 --- a/docs/Customization/Custom-Core.rst +++ b/docs/Customization/Custom-Core.rst @@ -199,8 +199,8 @@ more info. name = portName, id = IdRange(0, 1 << idBits)))))) -where ``portName`` and ``idBits`` are the parameter provides by the tile. Make sure to read :::ref:`node-tyoes` to check out what -type of nodes Chipyard supports and their parameters! +where ``portName`` and ``idBits`` (number of bits to represent a port ID) are the parameter provides by the tile. +Make sure to read :::ref:`node-tyoes` to check out what type of nodes Chipyard supports and their parameters! Also, by default, there are boundary buffers for both master and slave connections to the bus when they are leaving the tile, and you can override the following two functions to control how to buffer the bus requests/responses: @@ -291,11 +291,19 @@ The implementation class is of the following form: In the body of this class, you can look up any parameters by calling ``p({key})``, where ``{key}`` is the config key of the value you want to look up. For a list of available keys, see the appendix below. -If you create an AXI4 node (or equivalents), you will need to connect them to your core. +If you create an AXI4 node (or equivalents), you will need to connect them to your core. You can connect a port like this: -.. warning:: +.. code-block:: scala - TODO: Documenting bus connection + outer.myAXI4Node.out foreach { case (out, edgeOut) => + // Connect your module IO port to "out" + // The type of "out" here is AXI4Bundle, which is defined in generators/rocket-chip/src/main/scala/amba/axi4/Bundles.scala + // Please refer to this file for the definition of the ports. + // If you are using APB, check APBBundle in generators/rocket-chip/src/main/scala/amba/apb/Bundles.scala + // If you are using AHB, check AHBSlaveBundle or AHBMasterBundle in generators/rocket-chip/src/main/scala/amba/ahb/Bundles.scala + // (choose one depends on the type of AHB node you create) + // If you are using AXIS, check AXISBundle and AXISBundleBits in generators/rocket-chip/src/main/scala/amba/axis/Bundles.scala + } Integrate the Core ------------------ @@ -320,3 +328,83 @@ all custom cores. You can also create other config fragments to change other par Now you have finished all the steps to prepare your cores for Chipyard! To generate the custom core, simply follow the instructions in :::ref:`_custom_chisel` to add your project to the build system, then create a config by following the steps in :::ref:`_hetero_socs_`. You can now run any desired workflow for the new config just as you do for the built-in cores. + +Appendix: Common Config Keys +---------------------------- + +Chipyard provide a set of keys to store standard parameters. Below are some of the most common key used in core integration. +(Note that internal fields are hidden) + +.. code-block:: scala + + // keys + // Parameters exposed to the top-level design, set based on external requirements, etc. See RISC-V debug specs for more info. + case object DebugModuleKey extends Field[Option[DebugModuleParams]](Some(DebugModuleParams())) + case object BootROMParams extends Field[BootROMParams] // See chipyard boot process tutorial + case object CLINTKey extends Field[Option[CLINTParams]](None) // Core Local Interrupter setting (See SiFive Interrupt Cookbook) + case object PLICKey extends Field[Option[PLICParams]](None) // Platform Level Interrupt Controller setting (See SiFive Interrupt Cookbook) + case object CacheBlockBytes extends Field[Int](64) // # of bytes in a cache block + case object BroadcastKey extends Field(BroadcastParams()) // L2 Cache broadcast setting + case object BankedL2Key extends Field(BankedL2Params()) // L2 Cache memory setting + case object PgLevels extends Field[Int](2) // Page Level of virtual memory + case object ASIdBits extends Field[Int](0) // Max # of bits for Address Space Identifer (See specs) + case object ExtMem extends Field[Option[MemoryPortParams]](None) // External DRAM setting + case object ExtBus extends Field[Option[MasterPortParams]](None) // External (off-chip) output bus setting + case object ExtIn extends Field[Option[SlavePortParams]](None) // External (off-chip) input bus setting + case object MaxHartIdBits extends Field[Int] // Max # of bits used to represent a Hart ID + case object XLen extends Field[Int] // Instruction bits (32 or 64) + case object BuildRoCC extends Field[Seq[Parameters => LazyRoCC]](Nil) // See custom ROCC tutorial + + // Values + case class DebugModuleParams ( + nDMIAddrSize : Int = 7, // Size of the Debug Bus Address + nProgramBufferWords: Int = 16, // Number of 32-bit words for Program Buffer + nAbstractDataWords : Int = 4, // Number of 32-bit words for Abstract Commands + nScratch : Int = 1, // Number of scratch memories used + hasBusMaster : Boolean = false, // Whether or not a bus master should be included + clockGate : Boolean = true, // Use clock gating + maxSupportedSBAccess : Int = 32, // Maximum transaction size supported by System Bus Access logic. + supportQuickAccess : Boolean = false, // Whether or not to support the quick access command. + supportHartArray : Boolean = true, // Whether or not to implement the hart array register (if >1 hart). + nHaltGroups : Int = 1, // Number of halt groups (group of harts that are halted together) + nExtTriggers : Int = 0, // Number of extra triggers + hasHartResets : Boolean = false, // Whether harts can be reseted with debugging system + hasImplicitEbreak : Boolean = false, // There is an additional RO program buffer word containing an ebreak + hasAuthentication : Boolean = false, // Has authentication (to prevent unauthorized users to use debugging system) + crossingHasSafeReset : Boolean = true // Include "safe" logic in Async Crossings so that only one side needs to be reset. + ) + case class CLINTParams( + baseAddress: BigInt = 0x02000000, // Default interrupt handler base address for CLINT + intStages: Int = 0 // # of cycles (stages) interrupts are delayed + ) + case class PLICParams( + baseAddress: BigInt = 0xC000000, // Default interrupt handler base address for PLIC + maxPriorities: Int = 7, // Maximum allowed interrupt priority (cannot be over 7) + intStages: Int = 0, // # of cycles (stages) interrupts are delayed + maxHarts: Int = PLICConsts.maxMaxHarts // Maximum number or hart / core connected to it + ) + case class BroadcastParams( + nTrackers: Int = 4, // # of broadcast tracker + bufferless: Boolean = false // Bufferless broadcast + ) + case class BankedL2Params( + nBanks: Int = 1 // Number of banks in L2 cache + ) + case class MasterPortParams( + base: BigInt, // Base memory address for this port + size: BigInt, // Size of this external memory + beatBytes: Int, // Interface width in bytes + idBits: Int, // # of bits in the port ID + maxXferBytes: Int = 256, // Maximum bytes in one transfer transaction + executable: Boolean = true // If the data from this port can be executed as instruciton + ) + /** Specifies the width of external slave ports */ + case class SlavePortParams( + beatBytes: Int, // Interface width in bytes + idBits: Int, // # of bits in the port ID + sourceBits: Int // # of bits in the source address + ) + case class MemoryPortParams( + master: MasterPortParams, // The memory port setting + nMemoryChannels: Int // Number of memory channel + ) From 1c5bc7d0fff0dc20c8952e50b8bb724ede6da464 Mon Sep 17 00:00:00 2001 From: Zitao Fang Date: Wed, 24 Jun 2020 20:55:37 -0700 Subject: [PATCH 21/42] Integrate with new Rocket tile API --- .../src/main/scala/ConfigFragments.scala | 17 +-- .../chipyard/src/main/scala/CoreManager.scala | 123 ------------------ ...icCoreParams.scala => GenericParams.scala} | 37 +++++- .../chipyard/src/main/scala/TestSuites.scala | 26 ++-- .../scala/stage/phases/AddDefaultTests.scala | 8 +- 5 files changed, 56 insertions(+), 155 deletions(-) delete mode 100644 generators/chipyard/src/main/scala/CoreManager.scala rename generators/chipyard/src/main/scala/{GenericCoreParams.scala => GenericParams.scala} (82%) diff --git a/generators/chipyard/src/main/scala/ConfigFragments.scala b/generators/chipyard/src/main/scala/ConfigFragments.scala index 1d6281cf..d66d3a07 100644 --- a/generators/chipyard/src/main/scala/ConfigFragments.scala +++ b/generators/chipyard/src/main/scala/ConfigFragments.scala @@ -26,7 +26,7 @@ import sifive.blocks.devices.uart._ import sifive.blocks.devices.spi._ import chipyard.{BuildTop, BuildSystem} -import chipyard.{GenericTilesKey, GenericTileConfig} +import chipyard.GenericCanAttachTile /** * TODO: Why do we need this? @@ -65,11 +65,8 @@ class WithSPIFlash(size: BigInt = 0x10000000) extends Config((site, here, up) => class WithL2TLBs(entries: Int) extends Config((site, here, up) => { case TilesLocated(InSubsystem) => up(TilesLocated(InSubsystem), site) map { - case tp: RocketTileAttachParams => tp.copy(tileParams = tp.tileParams.copy( - core = tp.tileParams.core.copy(nL2TLBEntries = entries))) - case tp: BoomTileAttachParams => tp.copy(tileParams = tp.tileParams.copy( - core = tp.tileParams.core.copy(nL2TLBEntries = entries))) - case other => other + case GenericCanAttachTile(tp) => tp.copy(tileParams = tp.tileParams.copy( + core = tp.tileParams.core.copy(nL2TLBEntries = entries))).convert } }) @@ -110,7 +107,6 @@ class WithMultiRoCCHwacha(harts: Int*) extends Config((site, here, up) => { } }) - class WithTraceIO extends Config((site, here, up) => { case TilesLocated(InSubsystem) => up(TilesLocated(InSubsystem), site) map { case tp: BoomTileAttachParams => tp.copy(tileParams = tp.tileParams.copy( @@ -124,10 +120,7 @@ class WithTraceIO extends Config((site, here, up) => { class WithNPerfCounters(n: Int = 29) extends Config((site, here, up) => { case TilesLocated(InSubsystem) => up(TilesLocated(InSubsystem), site) map { - case tp: RocketTileAttachParams => tp.copy(tileParams = tp.tileParams.copy( - core = tp.tileParams.core.copy(nPerfCounters = n))) - case tp: BoomTileAttachParams => tp.copy(tileParams = tp.tileParams.copy( - core = tp.tileParams.core.copy(nPerfCounters = n))) - case other => other + case GenericCanAttachTile(tp) => tp.copy(tileParams = tp.tileParams.copy( + core = tp.tileParams.core.copy(nPerfCounters = n))).convert } }) diff --git a/generators/chipyard/src/main/scala/CoreManager.scala b/generators/chipyard/src/main/scala/CoreManager.scala deleted file mode 100644 index d013cc7c..00000000 --- a/generators/chipyard/src/main/scala/CoreManager.scala +++ /dev/null @@ -1,123 +0,0 @@ -package chipyard - -import scala.reflect.ClassTag -import scala.reflect.runtime.universe._ - -import chisel3._ - -import freechips.rocketchip.config.{Parameters, Config, Field, View} -import freechips.rocketchip.subsystem.{SystemBusKey, RocketTilesKey, RocketCrossingParams, RocketCrossingKey} -import freechips.rocketchip.diplomacy.{LazyModule, ClockCrossingType, ValName} -import freechips.rocketchip.diplomaticobjectmodel.logicaltree.LogicalTreeNode -import freechips.rocketchip.rocket._ -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 - - def keyEqual(key: Any): Boolean - def tileParamsLookup(implicit p: Parameters): Seq[TileParams] - - def instantiateTile(crossingLookup: (Seq[RocketCrossingParams], Int) => Seq[RocketCrossingParams], logicalTreeNode: LogicalTreeNode) - (implicit p: Parameters, valName: ValName): Seq[(TileParams, RocketCrossingParams, () => BaseTile)] -} - -// Implementation of third-party core entries -class CoreEntry[TileParamsT <: TileParams with Product: TypeTag, TileT <: BaseTile : TypeTag]( - val name: String, - tilesKey: Field[Seq[TileParamsT]], - crossingKey: Field[Seq[RocketCrossingParams]] -) extends CoreEntryBase { - // Use reflection to get the tile's constructor - private val mirror = runtimeMirror(getClass.getClassLoader) - private val tileClass = mirror.runtimeClass(typeOf[TileT].typeSymbol.asClass) - private val tileCtor = tileClass.getConstructors.filter(ctor => ctor.getParameterTypes()(4) == classOf[Parameters]).head - - def keyEqual(key: Any) = key == tilesKey - - // Tile parameter lookup using correct type - def tileParamsLookup(implicit p: Parameters) = p(tilesKey) - - // 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 { - case (param, crossing) => ( - param, - crossing, - (() => LazyModule(tileCtor.newInstance( - param, - crossing, - PriorityMuxHartIdFromSeq(tileParams), - logicalTreeNode, - p.asInstanceOf[Parameters] - ).asInstanceOf[TileT])) - ) - } - } -} - -// 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 { - // 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 -} diff --git a/generators/chipyard/src/main/scala/GenericCoreParams.scala b/generators/chipyard/src/main/scala/GenericParams.scala similarity index 82% rename from generators/chipyard/src/main/scala/GenericCoreParams.scala rename to generators/chipyard/src/main/scala/GenericParams.scala index 28db42b1..8ed0d0f3 100644 --- a/generators/chipyard/src/main/scala/GenericCoreParams.scala +++ b/generators/chipyard/src/main/scala/GenericParams.scala @@ -6,15 +6,12 @@ import scala.reflect.runtime.universe._ import chisel3._ import freechips.rocketchip.config.{Parameters, Config, Field, View} -import freechips.rocketchip.subsystem.{SystemBusKey, RocketTilesKey, RocketCrossingParams, RocketCrossingKey} +import freechips.rocketchip.subsystem._ import freechips.rocketchip.diplomacy.{LazyModule, ClockCrossingType, ValName} import freechips.rocketchip.diplomaticobjectmodel.logicaltree.LogicalTreeNode import freechips.rocketchip.rocket._ 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 => @@ -146,3 +143,35 @@ case class GenericTileParams( _origin = tileParams ) } + +case class GenericTileCrossingParamsLike( + val crossingType: ClockCrossingType, + val master: TilePortParamsLike, + val slave: TilePortParamsLike, + val _origin: TileCrossingParamsLike +) extends TileCrossingParamsLike with ConcreteBaseTrait[TileCrossingParamsLike] { + def this(crossing: TileCrossingParamsLike) = this( + crossingType = crossing.crossingType, + master = crossing.master, + slave = crossing.slave, + _origin = crossing + ) +} + +case class GenericCanAttachTileImpl( + val tileParams: GenericTileParams, + val crossingParams: TileCrossingParamsLike, + val lookup: LookupByHartIdImpl, + val _origin: CanAttachTile, +) extends ConcreteBaseTrait[CanAttachTile] { + def this(param: CanAttachTile) = this( + tileParams = new GenericTileParams(param.tileParams), + crossingParams = new GenericTileCrossingParamsLike(param.crossingParams), + lookup = param.lookup, + _origin = param + ) +} + +object GenericCanAttachTile { + def unapply(tile: CanAttachTile) = Some(new GenericCanAttachTileImpl(tile)) +} diff --git a/generators/chipyard/src/main/scala/TestSuites.scala b/generators/chipyard/src/main/scala/TestSuites.scala index a3565a53..77aab39b 100644 --- a/generators/chipyard/src/main/scala/TestSuites.scala +++ b/generators/chipyard/src/main/scala/TestSuites.scala @@ -3,8 +3,8 @@ package chipyard import scala.collection.mutable.{LinkedHashSet} import freechips.rocketchip.subsystem._ -import freechips.rocketchip.tile.{XLen} -import freechips.rocketchip.config.{Parameters} +import freechips.rocketchip.tile.{XLen, TileParams} +import freechips.rocketchip.config.{Parameters, Field, Config} import freechips.rocketchip.system.{TestGeneration, RegressionTestSuite, RocketTestSuite} import boom.common.{BoomTileAttachParams} @@ -83,16 +83,17 @@ class TestSuiteHelper if (cfg.fLen >= 64) addSuites(env.map(rv64ud)) } - if (coreParams.useAtomics) { - if (tileParams.dcache.flatMap(_.scratch).isEmpty) - addSuites(env.map(if (xlen == 64) rv64ua else rv32ua)) - else - addSuites(env.map(if (xlen == 64) rv64uaSansLRSC else rv32uaSansLRSC)) - } - if (coreParams.useCompressed) addSuites(env.map(if (xlen == 64) rv64uc else rv32uc)) - val (rvi, rvu) = - if (xlen == 64) ((if (vm) rv64i else rv64pi), rv64u) - else ((if (vm) rv32i else rv32pi), rv32u) + } + if (coreParams.useAtomics) { + if (tileParams.dcache.flatMap(_.scratch).isEmpty) + addSuites(env.map(if (xlen == 64) rv64ua else rv32ua)) + else + addSuites(env.map(if (xlen == 64) rv64uaSansLRSC else rv32uaSansLRSC)) + } + if (coreParams.useCompressed) addSuites(env.map(if (xlen == 64) rv64uc else rv32uc)) + val (rvi, rvu) = + if (xlen == 64) ((if (vm) rv64i else rv64pi), rv64u) + else ((if (vm) rv32i else rv32pi), rv32u) addSuites(rvi.map(_("p"))) addSuites(rvu.map(_("p"))) @@ -116,4 +117,3 @@ case object TestSuitesKey extends Field[(Seq[TileParams], TestSuiteHelper, Param class WithTestSuite(suiteFactory: (Seq[TileParams], TestSuiteHelper, Parameters) => Unit) extends Config((site, here, up) => { case TestSuitesKey => suiteFactory }) - diff --git a/generators/chipyard/src/main/scala/stage/phases/AddDefaultTests.scala b/generators/chipyard/src/main/scala/stage/phases/AddDefaultTests.scala index b170706e..623dbce4 100644 --- a/generators/chipyard/src/main/scala/stage/phases/AddDefaultTests.scala +++ b/generators/chipyard/src/main/scala/stage/phases/AddDefaultTests.scala @@ -15,10 +15,11 @@ import firrtl.options.Viewer.view import freechips.rocketchip.stage.RocketChipOptions import freechips.rocketchip.stage.phases.{RocketTestSuiteAnnotation} import freechips.rocketchip.system.{RocketTestSuite, TestGeneration} +import freechips.rocketchip.subsystem.{TilesLocated, InSubsystem} import freechips.rocketchip.util.HasRocketChipStageUtils import freechips.rocketchip.tile.XLen -import chipyard.{TestSuiteHelper, CoreManager} +import chipyard.TestSuiteHelper import chipyard.TestSuitesKey class AddDefaultTests extends Phase with PreservesAll[Phase] with HasRocketChipStageUtils { @@ -34,12 +35,13 @@ 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 + val tileParams = p(TilesLocated(InSubsystem)) map (tp => tp.tileParams) 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)) + p(TestSuitesKey).apply(tileParams, suiteHelper, p) else - CoreManager.cores(p) map (core => suiteHelper.addGenericTestSuites(core.tileParamsLookup)) + suiteHelper.addGenericTestSuites(tileParams) // if hwacha parameter exists then generate its tests // TODO: find a more elegant way to do this. either through From 1dd3ea4aebdcc720af33495fb12b364b643b76de Mon Sep 17 00:00:00 2001 From: David Biancolin Date: Sat, 27 Jun 2020 13:44:52 -0700 Subject: [PATCH 22/42] Update TargetConfigs.scala --- generators/firechip/src/main/scala/TargetConfigs.scala | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/generators/firechip/src/main/scala/TargetConfigs.scala b/generators/firechip/src/main/scala/TargetConfigs.scala index 830188f3..87662b03 100644 --- a/generators/firechip/src/main/scala/TargetConfigs.scala +++ b/generators/firechip/src/main/scala/TargetConfigs.scala @@ -125,7 +125,8 @@ class FireSimQuadRocketConfig extends Config( new WithFireSimConfigTweaks ++ new chipyard.QuadRocketConfig) -// Should fit on all supported hosts +// A stripped down configuration that should fit on all supported hosts. +// Flat to avoid having to reorganize the config class hierarchy to remove certain features class FireSimSmallSystemConfig extends Config( new WithDefaultFireSimBridges ++ new WithDefaultMemModel ++ From 7b5f474b041a30ff06eb29ee8dbf6914277ba171 Mon Sep 17 00:00:00 2001 From: Zitao Fang Date: Sun, 28 Jun 2020 21:26:50 -0700 Subject: [PATCH 23/42] Finished Custom Core Docs --- docs/Customization/Custom-Core.rst | 26 +++++++------------ docs/Customization/index.rst | 1 + .../NodeTypes.rst | 2 ++ docs/TileLink-Diplomacy-Reference/Widgets.rst | 2 ++ 4 files changed, 15 insertions(+), 16 deletions(-) diff --git a/docs/Customization/Custom-Core.rst b/docs/Customization/Custom-Core.rst index 6d0a9956..e2723336 100644 --- a/docs/Customization/Custom-Core.rst +++ b/docs/Customization/Custom-Core.rst @@ -4,7 +4,7 @@ Adding a custom core ==================== You may want to add a custom RISC-V core to Chipyard generator. If the top module of your core is not in Chisel, -you will first need to create a Verilog blackbox for it. See ::ref:`_incorporating-verilog-blocks` for instructions. +you will first need to create a Verilog blackbox for it. See :ref:`incorporating-verilog-blocks` for instructions. Once you have a top module in Chisel, you are ready to create integrate it with Chipyard. .. note:: @@ -184,7 +184,7 @@ in the tile class. Below is an example of how to connect a core using AXI4 to th := AXI4Fragmenter() // deal with multi-beat xacts := memAXI4Node) // The custom node, see below -Remember, you may not need all of these intermediate widgets. See :::ref:`Diplomatic-Widgets` for the meaning of each intermediate +Remember, you may not need all of these intermediate widgets. See :ref:`diplomatic_widgets` for the meaning of each intermediate widget. If you are using TileLink, then you only need the tap node and the TileLink node used by your components. Also, Chipyard support AHB, APB and AXIS, and most of the AXI4 widgets has equivalent widget for these bus protocol. See the reference page for more info. @@ -200,7 +200,7 @@ more info. id = IdRange(0, 1 << idBits)))))) where ``portName`` and ``idBits`` (number of bits to represent a port ID) are the parameter provides by the tile. -Make sure to read :::ref:`node-tyoes` to check out what type of nodes Chipyard supports and their parameters! +Make sure to read :ref:`node_types` to check out what type of nodes Chipyard supports and their parameters! Also, by default, there are boundary buffers for both master and slave connections to the bus when they are leaving the tile, and you can override the following two functions to control how to buffer the bus requests/responses: @@ -210,7 +210,7 @@ can override the following two functions to control how to buffer the bus reques protected def makeMasterBoundaryBuffers(implicit p: Parameters): TLBuffer protected def makeSlaveBoundaryBuffers(implicit p: Parameters): TLBuffer -You can find more information on ``TLBuffer`` in :::ref:`Diplomatic-Widgets`. +You can find more information on ``TLBuffer`` in :ref:`diplomatic_widgets`. Interrupt --------- @@ -313,20 +313,14 @@ the current config. An example of such config will be like this: .. code-block:: scala - class WithNMyCores(n: Int) extends Config( - new RegisterCore(new CoreEntry[MyTileParams, MyTile]("MyCore", MyTilesKey, MyCrossingKey)) ++ - new Config((site, here, up) => { - case MyTilesKey => { - List.tabulate(n)(i => MyTileParams(hartId = i)) - } - }) - ) - -Where ``RegisterCore`` will register the core with chipyard so that it can be recognized by generic config. This is required for -all custom cores. You can also create other config fragments to change other parameters. + class WithNMyCores(n: Int) extends Config((site, here, up) => { + case MyTilesKey => { + List.tabulate(n)(i => MyTileParams(hartId = i)) + } + }) Now you have finished all the steps to prepare your cores for Chipyard! To generate the custom core, simply follow the instructions -in :::ref:`_custom_chisel` to add your project to the build system, then create a config by following the steps in :::ref:`_hetero_socs_`. +in :ref:`custom_chisel` to add your project to the build system, then create a config by following the steps in :ref:`hetero_socs_`. You can now run any desired workflow for the new config just as you do for the built-in cores. Appendix: Common Config Keys diff --git a/docs/Customization/index.rst b/docs/Customization/index.rst index 38fdf622..a7b571b6 100644 --- a/docs/Customization/index.rst +++ b/docs/Customization/index.rst @@ -37,6 +37,7 @@ We recommend reading all these pages in order. Hit next to get started! Heterogeneous-SoCs Custom-Chisel + Custom-Core RoCC-or-MMIO RoCC-Accelerators MMIO-Peripherals diff --git a/docs/TileLink-Diplomacy-Reference/NodeTypes.rst b/docs/TileLink-Diplomacy-Reference/NodeTypes.rst index ddb53c9f..32953944 100644 --- a/docs/TileLink-Diplomacy-Reference/NodeTypes.rst +++ b/docs/TileLink-Diplomacy-Reference/NodeTypes.rst @@ -1,3 +1,5 @@ +.. _node_types: + TileLink Node Types =================== diff --git a/docs/TileLink-Diplomacy-Reference/Widgets.rst b/docs/TileLink-Diplomacy-Reference/Widgets.rst index 7eba871b..791c1b9b 100644 --- a/docs/TileLink-Diplomacy-Reference/Widgets.rst +++ b/docs/TileLink-Diplomacy-Reference/Widgets.rst @@ -1,3 +1,5 @@ +.. _diplomatic_widgets: + Diplomatic Widgets ================== From c85d8c4211c3c888a0ba0b80a92ee5d5b23bbc39 Mon Sep 17 00:00:00 2001 From: Zitao Fang Date: Mon, 29 Jun 2020 11:42:34 -0700 Subject: [PATCH 24/42] Remove generic parameter from this PR --- .../src/main/scala/ConfigFragments.scala | 48 +++-- .../src/main/scala/GenericParams.scala | 177 ------------------ .../chipyard/src/main/scala/TestSuites.scala | 13 +- .../src/main/scala/config/BoomConfigs.scala | 1 + .../src/main/scala/config/HeteroConfigs.scala | 1 + .../src/main/scala/config/RocketConfigs.scala | 1 + .../scala/stage/phases/AddDefaultTests.scala | 18 +- 7 files changed, 42 insertions(+), 217 deletions(-) delete mode 100644 generators/chipyard/src/main/scala/GenericParams.scala diff --git a/generators/chipyard/src/main/scala/ConfigFragments.scala b/generators/chipyard/src/main/scala/ConfigFragments.scala index d66d3a07..da048ff1 100644 --- a/generators/chipyard/src/main/scala/ConfigFragments.scala +++ b/generators/chipyard/src/main/scala/ConfigFragments.scala @@ -25,8 +25,7 @@ import sifive.blocks.devices.gpio._ import sifive.blocks.devices.uart._ import sifive.blocks.devices.spi._ -import chipyard.{BuildTop, BuildSystem} -import chipyard.GenericCanAttachTile +import chipyard.{BuildTop, BuildSystem, TestSuitesKey, TestSuiteHelper} /** * TODO: Why do we need this? @@ -65,8 +64,11 @@ class WithSPIFlash(size: BigInt = 0x10000000) extends Config((site, here, up) => class WithL2TLBs(entries: Int) extends Config((site, here, up) => { case TilesLocated(InSubsystem) => up(TilesLocated(InSubsystem), site) map { - case GenericCanAttachTile(tp) => tp.copy(tileParams = tp.tileParams.copy( - core = tp.tileParams.core.copy(nL2TLBEntries = entries))).convert + case tp: RocketTileAttachParams => tp.copy(tileParams = tp.tileParams.copy( + core = tp.tileParams.core.copy(nL2TLBEntries = entries))) + case tp: BoomTileAttachParams => tp.copy(tileParams = tp.tileParams.copy( + core = tp.tileParams.core.copy(nL2TLBEntries = entries))) + case other => other } }) @@ -97,15 +99,18 @@ class WithMultiRoCC extends Config((site, here, up) => { * * @param harts harts to specify which will get a Hwacha */ -class WithMultiRoCCHwacha(harts: Int*) extends Config((site, here, up) => { - case MultiRoCCKey => { - up(MultiRoCCKey, site) ++ harts.distinct.map{ i => - (i -> Seq((p: Parameters) => { - LazyModule(new Hwacha()(p)).suggestName("hwacha") - })) +class WithMultiRoCCHwacha(harts: Int*) extends Config( + new chipyard.config.WithHwachaTest ++ + new Config((site, here, up) => { + case MultiRoCCKey => { + up(MultiRoCCKey, site) ++ harts.distinct.map{ i => + (i -> Seq((p: Parameters) => { + LazyModule(new Hwacha()(p)).suggestName("hwacha") + })) + } } - } -}) + }) +) class WithTraceIO extends Config((site, here, up) => { case TilesLocated(InSubsystem) => up(TilesLocated(InSubsystem), site) map { @@ -120,7 +125,22 @@ class WithTraceIO extends Config((site, here, up) => { class WithNPerfCounters(n: Int = 29) extends Config((site, here, up) => { case TilesLocated(InSubsystem) => up(TilesLocated(InSubsystem), site) map { - case GenericCanAttachTile(tp) => tp.copy(tileParams = tp.tileParams.copy( - core = tp.tileParams.core.copy(nPerfCounters = n))).convert + case tp: RocketTileAttachParams => tp.copy(tileParams = tp.tileParams.copy( + core = tp.tileParams.core.copy(nPerfCounters = n))) + case tp: BoomTileAttachParams => tp.copy(tileParams = tp.tileParams.copy( + core = tp.tileParams.core.copy(nPerfCounters = n))) + case other => other } }) + +class WithHwachaTest extends Config((site, here, up) => { + case TestSuitesKey => (tileParams: Seq[TileParams], suiteHelper: TestSuiteHelper, p: Parameters) => { + up(TestSuitesKey).apply(tileParams, suiteHelper, p) + import hwacha.HwachaTestSuites._ + suiteHelper.addSuites(rv64uv.map(_("p"))) + suiteHelper.addSuites(rv64uv.map(_("vp"))) + suiteHelper.addSuite(rv64sv("p")) + suiteHelper.addSuite(hwachaBmarks) + "SRC_EXTENSION = $(base_dir)/hwacha/$(src_path)/*.scala" + "\nDISASM_EXTENSION = --extension=hwacha" + } +}) \ No newline at end of file diff --git a/generators/chipyard/src/main/scala/GenericParams.scala b/generators/chipyard/src/main/scala/GenericParams.scala deleted file mode 100644 index 8ed0d0f3..00000000 --- a/generators/chipyard/src/main/scala/GenericParams.scala +++ /dev/null @@ -1,177 +0,0 @@ -package chipyard - -import scala.reflect.ClassTag -import scala.reflect.runtime.universe._ - -import chisel3._ - -import freechips.rocketchip.config.{Parameters, Config, Field, View} -import freechips.rocketchip.subsystem._ -import freechips.rocketchip.diplomacy.{LazyModule, ClockCrossingType, ValName} -import freechips.rocketchip.diplomaticobjectmodel.logicaltree.LogicalTreeNode -import freechips.rocketchip.rocket._ -import freechips.rocketchip.tile._ - -// 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( - val bootFreqHz: BigInt, - val useVM: Boolean, - val useUser: Boolean, - val useSupervisor: Boolean, - val useDebug: Boolean, - val useAtomics: Boolean, - val useAtomicsOnlyForIO: Boolean, - val useCompressed: Boolean, - override val useVector: Boolean, - val useSCIE: Boolean, - val useRVE: Boolean, - val mulDiv: Option[MulDivParams], - val fpu: Option[FPUParams], - val fetchWidth: Int, - val decodeWidth: Int, - val retireWidth: Int, - val instBits: Int, - val nLocalInterrupts: Int, - val nPMPs: Int, - val pmpGranularity: Int, - val nBreakpoints: Int, - val useBPWatch: Boolean, - val nPerfCounters: Int, - val haveBasicCounters: Boolean, - val haveFSDirty: Boolean, - val misaWritable: Boolean, - val haveCFlush: Boolean, - val nL2TLBEntries: Int, - val mtvecInit: Option[BigInt], - val mtvecWritable: Boolean, - // The original object - val _origin: CoreParams -) extends CoreParams with ConcreteBaseTrait[CoreParams] { - def this(coreParams: CoreParams) = this( - bootFreqHz = coreParams.bootFreqHz, - useVM = coreParams.useVM, - useUser = coreParams.useUser, - useSupervisor = coreParams.useSupervisor, - useDebug = coreParams.useDebug, - useAtomics = coreParams.useAtomics, - useAtomicsOnlyForIO = coreParams.useAtomicsOnlyForIO, - useCompressed = coreParams.useCompressed, - useVector = coreParams.useVector, - useSCIE = coreParams.useSCIE, - useRVE = coreParams.useRVE, - mulDiv = coreParams.mulDiv, - fpu = coreParams.fpu, - fetchWidth = coreParams.fetchWidth, - decodeWidth = coreParams.decodeWidth, - retireWidth = coreParams.retireWidth, - instBits = coreParams.instBits, - nLocalInterrupts = coreParams.nLocalInterrupts, - nPMPs = coreParams.nPMPs, - pmpGranularity = coreParams.pmpGranularity, - nBreakpoints = coreParams.nBreakpoints, - useBPWatch = coreParams.useBPWatch, - nPerfCounters = coreParams.nPerfCounters, - haveBasicCounters = coreParams.haveBasicCounters, - haveFSDirty = coreParams.haveFSDirty, - misaWritable = coreParams.misaWritable, - haveCFlush = coreParams.haveCFlush, - nL2TLBEntries = coreParams.nL2TLBEntries, - mtvecInit = coreParams.mtvecInit, - mtvecWritable = coreParams.mtvecWritable, - - _origin = coreParams - ) - - // Implement abstract function as placeholder - def lrscCycles: Int = _origin.lrscCycles -} - -case class GenericTileParams( - val core: GenericCoreParams, - val icache: Option[ICacheParams], - val dcache: Option[DCacheParams], - val btb: Option[BTBParams], - val hartId: Int, - val beuAddr: Option[BigInt], - val blockerCtrlAddr: Option[BigInt], - val name: Option[String], - // The original object - val _origin: TileParams, -) extends TileParams with ConcreteBaseTrait[TileParams] { - // Copy constructor to build the params - def this(tileParams: TileParams) = this( - core = new GenericCoreParams(tileParams.core), - icache = tileParams.icache, - dcache = tileParams.dcache, - btb = tileParams.btb, - hartId = tileParams.hartId, - beuAddr = tileParams.beuAddr, - blockerCtrlAddr = tileParams.blockerCtrlAddr, - name = tileParams.name, - - _origin = tileParams - ) -} - -case class GenericTileCrossingParamsLike( - val crossingType: ClockCrossingType, - val master: TilePortParamsLike, - val slave: TilePortParamsLike, - val _origin: TileCrossingParamsLike -) extends TileCrossingParamsLike with ConcreteBaseTrait[TileCrossingParamsLike] { - def this(crossing: TileCrossingParamsLike) = this( - crossingType = crossing.crossingType, - master = crossing.master, - slave = crossing.slave, - _origin = crossing - ) -} - -case class GenericCanAttachTileImpl( - val tileParams: GenericTileParams, - val crossingParams: TileCrossingParamsLike, - val lookup: LookupByHartIdImpl, - val _origin: CanAttachTile, -) extends ConcreteBaseTrait[CanAttachTile] { - def this(param: CanAttachTile) = this( - tileParams = new GenericTileParams(param.tileParams), - crossingParams = new GenericTileCrossingParamsLike(param.crossingParams), - lookup = param.lookup, - _origin = param - ) -} - -object GenericCanAttachTile { - def unapply(tile: CanAttachTile) = Some(new GenericCanAttachTileImpl(tile)) -} diff --git a/generators/chipyard/src/main/scala/TestSuites.scala b/generators/chipyard/src/main/scala/TestSuites.scala index 77aab39b..9ca2c08c 100644 --- a/generators/chipyard/src/main/scala/TestSuites.scala +++ b/generators/chipyard/src/main/scala/TestSuites.scala @@ -107,13 +107,8 @@ 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 +case object TestSuitesKey extends Field[(Seq[TileParams], TestSuiteHelper, Parameters) => String]((tiles, helper, p) => { + helper.addGenericTestSuites(tiles)(p) + // Return an empty string as makefile additional snippets + "" }) diff --git a/generators/chipyard/src/main/scala/config/BoomConfigs.scala b/generators/chipyard/src/main/scala/config/BoomConfigs.scala index 7b66e3b3..414f10af 100644 --- a/generators/chipyard/src/main/scala/config/BoomConfigs.scala +++ b/generators/chipyard/src/main/scala/config/BoomConfigs.scala @@ -106,6 +106,7 @@ class HwachaLargeBoomConfig extends Config( new chipyard.config.WithBootROM ++ new chipyard.config.WithUART ++ new chipyard.config.WithL2TLBs(1024) ++ + new chipyard.config.WithHwachaTest ++ new hwacha.DefaultHwachaConfig ++ // use Hwacha vector accelerator new freechips.rocketchip.subsystem.WithNoMMIOPort ++ new freechips.rocketchip.subsystem.WithNoSlavePort ++ diff --git a/generators/chipyard/src/main/scala/config/HeteroConfigs.scala b/generators/chipyard/src/main/scala/config/HeteroConfigs.scala index a7d1c133..4930ddee 100644 --- a/generators/chipyard/src/main/scala/config/HeteroConfigs.scala +++ b/generators/chipyard/src/main/scala/config/HeteroConfigs.scala @@ -36,6 +36,7 @@ class HwachaLargeBoomAndHwachaRocketConfig extends Config( new chipyard.config.WithBootROM ++ new chipyard.config.WithUART ++ new chipyard.config.WithL2TLBs(1024) ++ + new chipyard.config.WithHwachaTest ++ new hwacha.DefaultHwachaConfig ++ // add hwacha to all harts new boom.common.WithNLargeBooms(1) ++ new freechips.rocketchip.subsystem.WithNoMMIOPort ++ diff --git a/generators/chipyard/src/main/scala/config/RocketConfigs.scala b/generators/chipyard/src/main/scala/config/RocketConfigs.scala index 06257c7b..566e2757 100644 --- a/generators/chipyard/src/main/scala/config/RocketConfigs.scala +++ b/generators/chipyard/src/main/scala/config/RocketConfigs.scala @@ -34,6 +34,7 @@ class HwachaRocketConfig extends Config( new chipyard.config.WithBootROM ++ new chipyard.config.WithUART ++ new chipyard.config.WithL2TLBs(1024) ++ + new chipyard.config.WithHwachaTest ++ new hwacha.DefaultHwachaConfig ++ // use Hwacha vector accelerator new freechips.rocketchip.subsystem.WithNoMMIOPort ++ new freechips.rocketchip.subsystem.WithNoSlavePort ++ diff --git a/generators/chipyard/src/main/scala/stage/phases/AddDefaultTests.scala b/generators/chipyard/src/main/scala/stage/phases/AddDefaultTests.scala index 623dbce4..177d26b0 100644 --- a/generators/chipyard/src/main/scala/stage/phases/AddDefaultTests.scala +++ b/generators/chipyard/src/main/scala/stage/phases/AddDefaultTests.scala @@ -38,24 +38,8 @@ class AddDefaultTests extends Phase with PreservesAll[Phase] with HasRocketChipS val tileParams = p(TilesLocated(InSubsystem)) map (tp => tp.tileParams) if (p.lift(XLen).nonEmpty) // If a custom test suite is set up, use the custom test suite - if (p.lift(TestSuitesKey).nonEmpty) - p(TestSuitesKey).apply(tileParams, suiteHelper, p) - else - suiteHelper.addGenericTestSuites(tileParams) + annotations += CustomMakefragSnippet(p(TestSuitesKey).apply(tileParams, suiteHelper, p)) - // if hwacha parameter exists then generate its tests - // TODO: find a more elegant way to do this. either through - // trying to disambiguate BuildRoCC, having a AccelParamsKey, - // or having the Accelerator/Tile add its own tests - import hwacha.HwachaTestSuites._ - if (Try(p(hwacha.HwachaNLanes)).getOrElse(0) > 0) { - suiteHelper.addSuites(rv64uv.map(_("p"))) - suiteHelper.addSuites(rv64uv.map(_("vp"))) - suiteHelper.addSuite(rv64sv("p")) - suiteHelper.addSuite(hwachaBmarks) - annotations += CustomMakefragSnippet( - "SRC_EXTENSION = $(base_dir)/hwacha/$(src_path)/*.scala" + "\nDISASM_EXTENSION = --extension=hwacha") - } RocketTestSuiteAnnotation(suiteHelper.suites.values.toSeq) +: annotations } From d77c4afb36ec37414dadbef63904376f8e0853d3 Mon Sep 17 00:00:00 2001 From: Zitao Fang Date: Mon, 29 Jun 2020 12:05:24 -0700 Subject: [PATCH 25/42] Rollback .gitignore --- .gitignore | 4 ---- 1 file changed, 4 deletions(-) diff --git a/.gitignore b/.gitignore index 57467069..35d9b2d8 100644 --- a/.gitignore +++ b/.gitignore @@ -10,10 +10,6 @@ target *# *~ .idea -.bloop -.metals -project/metals.sbt -.vscode .DS_Store env.sh riscv-tools-install From 104c350a59af995d0d36affc5f1203582be838ca Mon Sep 17 00:00:00 2001 From: Zitao Fang Date: Thu, 2 Jul 2020 15:56:15 -0700 Subject: [PATCH 26/42] Custom Core Integration Doc, 1st Revision --- docs/Customization/Custom-Core.rst | 113 +++++++++----------- docs/TileLink-Diplomacy-Reference/index.rst | 2 + 2 files changed, 51 insertions(+), 64 deletions(-) diff --git a/docs/Customization/Custom-Core.rst b/docs/Customization/Custom-Core.rst index e2723336..dcf2c257 100644 --- a/docs/Customization/Custom-Core.rst +++ b/docs/Customization/Custom-Core.rst @@ -7,34 +7,32 @@ You may want to add a custom RISC-V core to Chipyard generator. If the top modul you will first need to create a Verilog blackbox for it. See :ref:`incorporating-verilog-blocks` for instructions. Once you have a top module in Chisel, you are ready to create integrate it with Chipyard. +``generators/ariane/src/main/scala/ArianeTile.scala`` and ``generators/boom/src/main/scala/common/tile.scala`` +provide two examples of how to integrate a core. + .. note:: - RoCC is not supported by custom core currently. Please use Rocket or Boom if you need to use RoCC. + RoCC is not supported by custom core currently. Please use Rocket or Boom as the RoCC base core if you need to use RoCC. Parameter Case Classes ---------------------- -Chipyard will generate a core for every ``TileParams`` object it discovered in the current config. -``TileParams`` is a trait containing the information needed to create a tile, and every custom core must implement -their own version of ``TileParams``, as well as ``CoreParams`` which is passed as a field in ``TileParams``. +Chipyard will generate a core for every ``InstantiableTileParams`` object it discovered in the current config. +This object is derived from``TileParams``, a trait containing the information needed to create a tile. All cores must have +their own implementation of ``InstantiableTileParams``, as well as ``CoreParams`` which is passed as a field in ``TileParams``. -``TileParams`` holds the parameters that are the same for every generated core, while ``CoreParams`` contains those -that can vary from cores to cores. They must be implemented as case classes with fields that can be overridden by +``TileParams`` holds the parameters for the tile, which are the same for every generated core, while ``CoreParams`` +contains the parameters for individual cores. They must be implemented as case classes with fields that can be overridden by other config fragments as the constructor parameters. See the appendix at the bottom of the page for a list of variable to be implemented. You can also add custom fields to them, but standard fields should always be preferred. -Now you have your parameter classes, you will need config keys to hold them. There are two required keys: +``InstantiableTileParams[TileType]`` holds the constructor of ``TileType`` on top of the fields of ``TileParams``. +All custom cores will also need to implement ``instantiate()`` in their tile parameter class to return a new instance +of the tile class ``TileType``. -.. code-block:: scala - - case object MyTilesKey extends Field[Seq[MyTileParams]](Nil) - case object MyCrossingKey extends Field[Seq[RocketCrossingParams]](List(RocketCrossingParams())) - -``MyCrossingKey`` here is used to store information about the clock-crossing behavior of the core, and it is normally -set to its default values. - -``TileParams`` and ``CoreParams`` contains the following fields (you may ignore any fields marked "Rocket specific" and -use their default values, although it is recommended to use them if you need a custom field with similar purposes) : +``TileParams``, ``InstantiableTileParams[TileType]`` and ``CoreParams`` contains the following fields (you may ignore +any fields marked "Rocket specific" and use their default values, although it is recommended to use them if you +need a custom field with similar purposes): .. code-block:: scala @@ -49,6 +47,11 @@ use their default values, although it is recommended to use them if you need a c val name: Option[String] // Name of the core } + abstract class InstantiableTileParams[TileType <: BaseTile] extends TileParams { + def instantiate(crossing: TileCrossingParamsLike, lookup: LookupByHartIdImpl) + (implicit p: Parameters): TileType + } + trait CoreParams { val bootFreqHz: BigInt // Frequency val useVM: Boolean // Support virtual memory @@ -87,7 +90,7 @@ use their default values, although it is recommended to use them if you need a c def hasSupervisorMode: Boolean = useSupervisor || useVM def instBytes: Int = instBits / 8 def fetchBytes: Int = fetchWidth * instBytes - // Rocket specific: Longest possible latency of Rocket core D1 cache. Simply set it to the default value 80. + // Rocket specific: Longest possible latency of Rocket core D1 cache. Simply set it to the default value 80 if you don't use it. def lrscCycles: Int def dcacheReqTagBits: Int = 6 @@ -109,14 +112,23 @@ use their default values, although it is recommended to use them if you need a c Most of the fields here are originally designed for Rocket core and contains some architecture-specific details, but many of them are general enough to be useful for other cores. It is strongly recommended to use these fields instead -of creating your own custom fields when applicable. +of creating your own custom fields when applicable. + +.. note:: + + Implementations may choose to ignore some fields here or use them in a non-standard way, but using an inaccurate + value may break Chipyard components that rely on them (e.g. inaccurate indication of supported ISA extension will + result in incorrect test suite being generated) as well as any custom module that use them. ALWAYS document any + fields you ignore or with altered usage in your core implementation, and if you are implementing other devices that + would look up these config values, also document them. "Rocket specific" values are generally safe to ignore, but + you should document them if you use them. Tile Class ---------- -In Chipyard, all connections with other components on SoC are defined a core's `Tile` class, while the implementation -of the actual hardware are in the implementation class. This structure allows Chipyard to use the Diplomacy framework -to resolve paramters and connections before elaboration. +In Chipyard, all Tiles are diplomatically instantiated. In the first phase, diplomatic nodes which specify Tile-to-System +interconnects are evaluated, while in the second "Module Implementation" phase, hardware is elaborated. +See :ref:`tilelink_and_diplomacy` for more details. All tile classes implement ``BaseTile`` and will normally implement ``SinksExternalInterrupts`` and ``SourcesExternalNotifications``, which allow the tile to accept external interrupt. A typical tile has the following form: @@ -169,7 +181,8 @@ TileLink Connection ------------------- Chipyard use TileLink as its onboard bus protocol, and if your core doesn't use TileLink, you will need to convert them -in the tile class. Below is an example of how to connect a core using AXI4 to the TileLink bus: +in the tile class. Below is an example of how to connect a core using AXI4 to the TileLink bus with converters provided by +Chipyards: .. code-block:: scala @@ -185,9 +198,12 @@ in the tile class. Below is an example of how to connect a core using AXI4 to th := memAXI4Node) // The custom node, see below Remember, you may not need all of these intermediate widgets. See :ref:`diplomatic_widgets` for the meaning of each intermediate -widget. If you are using TileLink, then you only need the tap node and the TileLink node used by your components. Also, Chipyard -support AHB, APB and AXIS, and most of the AXI4 widgets has equivalent widget for these bus protocol. See the reference page for -more info. +widget. If you are using TileLink, then you only need the tap node and the TileLink node used by your components. Chipyard also +provides converters for AHB, APB and AXIS, and most of the AXI4 widgets has equivalent widget for these bus protocol; see the +source files in ``generators/rocket-chip/src/main/scala/amba`` for more info. + +If you are using other bus protocol, you may implement your own converters, using the files in ``generators/rocket-chip/src/main/scala/amba`` +as the template, but it is not recommended unless you are familiar with TileLink. ``memAXI4Node`` is an AXI4 master node and is defined as following in our example: @@ -232,7 +248,8 @@ The definition of ``TileInterrupts`` is } This function should be in the implementation class since it involves hardware generation. -Also, the tile can also notify other cores or devices for some events by calling following functions (in implementation class): +Also, the tile can also notify other cores or devices for some events by calling following functions in ``SourcesExternalNotifications`` +from the implementation class: .. code-block:: scala @@ -241,39 +258,6 @@ Also, the tile can also notify other cores or devices for some events by calling reportCease(could_cease: Option[Bool], quiescenceCycles: Int = 8) // Triggered when the core stop retiring instructions (like clock gating) reportWFI(could_wfi: Option[Bool]) // Triggered when a WFI instruction is executed -Trace (Optional) ----------------- - -Chipyard provides a set of ports for instruction trace that conforms with related RISC-V standard. -If you are using FireSim, it is recommended to implement these trace ports to enable FireSim to read trace. - -There are one inbound node ``traceAuxSinkNode.bundle: TraceAux`` and two outbound nodes ``traceCoreSourceNode.bundle: TraceCoreInterface`` -and ``bpwatchSourceNode.bundle: Vec[BPWatch]``. Note that the length of ``bpwatchSourceNode`` is equal to the max number of -breakpoints (set by ``nBreakpoints`` in ``CoreParams``). Below is the definition of these types: - -.. code-block:: scala - - // Control signal from the external tracer - class TraceAux extends Bundle { - val enable = Bool() // Enable trace output - val stall = Bool() // If true, the core should stall - } - // Check RISC-V Processor Trace spec V1.0 for more information of this interface - class TraceCoreInterface (val params: TraceCoreParams) extends Bundle { - val group = Vec(params.nGroups, new TraceCoreGroup(params)) - val priv = UInt(4.W) - val tval = UInt(params.xlen.W) - val cause = UInt(params.xlen.W) - } - // Address Breakpoint and watchpoint info (n is the retire width) - class BPWatch (val n: Int) extends Bundle() { - val valid = Vec(n, Bool()) // Valid bit of the output - val rvalid = Vec(n, Bool()) // Break on read - val wvalid = Vec(n, Bool()) // Break on write - val ivalid = Vec(n, Bool()) // Break on execute - val action = UInt(3.W) // Exception code (3 usually) - } - Implementation Class -------------------- @@ -313,12 +297,13 @@ the current config. An example of such config will be like this: .. code-block:: scala - class WithNMyCores(n: Int) extends Config((site, here, up) => { - case MyTilesKey => { - List.tabulate(n)(i => MyTileParams(hartId = i)) - } + class WithNMyCores(n: Int, hartidOffset: Int) extends Config((site, here, up) => { + case TilesLocated(InSubsystem) => up(TilesLocated(InSubsystem)) :++ List.tabulate(n)(i => MyTileParams(hartId = i + hartidOffset)) }) +Chipyard looks up the tile parameters in the field ``TilesLocated(InSubsystem)``, whose type is a list of ``InstantiableTileParams``. +This config fragment simply appends new tile parameters to the end of this list. + Now you have finished all the steps to prepare your cores for Chipyard! To generate the custom core, simply follow the instructions in :ref:`custom_chisel` to add your project to the build system, then create a config by following the steps in :ref:`hetero_socs_`. You can now run any desired workflow for the new config just as you do for the built-in cores. diff --git a/docs/TileLink-Diplomacy-Reference/index.rst b/docs/TileLink-Diplomacy-Reference/index.rst index dfc2ec5a..9c70287d 100644 --- a/docs/TileLink-Diplomacy-Reference/index.rst +++ b/docs/TileLink-Diplomacy-Reference/index.rst @@ -1,3 +1,5 @@ +.. _tilelink_and_diplomacy: + TileLink and Diplomacy Reference ================================ From 744e73fa9223c9b5571b91d388566b8a07ba8949 Mon Sep 17 00:00:00 2001 From: Zitao Fang Date: Sun, 5 Jul 2020 21:05:21 -0700 Subject: [PATCH 27/42] Editing Docs --- docs/Customization/Custom-Core.rst | 179 ++++++------------ .../src/main/scala/example/TutorialTile.scala | 179 ++++++++++++++++++ 2 files changed, 241 insertions(+), 117 deletions(-) create mode 100644 generators/chipyard/src/main/scala/example/TutorialTile.scala diff --git a/docs/Customization/Custom-Core.rst b/docs/Customization/Custom-Core.rst index dcf2c257..17b9b125 100644 --- a/docs/Customization/Custom-Core.rst +++ b/docs/Customization/Custom-Core.rst @@ -3,21 +3,24 @@ Adding a custom core ==================== -You may want to add a custom RISC-V core to Chipyard generator. If the top module of your core is not in Chisel, -you will first need to create a Verilog blackbox for it. See :ref:`incorporating-verilog-blocks` for instructions. -Once you have a top module in Chisel, you are ready to create integrate it with Chipyard. - -``generators/ariane/src/main/scala/ArianeTile.scala`` and ``generators/boom/src/main/scala/common/tile.scala`` -provide two examples of how to integrate a core. +You may want to integrate a custom RISC-V core into the Chipyard framework. This documentation page provides a step-to-step +instruction on how to achieve this. .. note:: - RoCC is not supported by custom core currently. Please use Rocket or Boom as the RoCC base core if you need to use RoCC. + RoCC is currently not supported by cores other than Rocket and BOOM. Please use Rocket or BOOM as the RoCC base core if you need to use RoCC. -Parameter Case Classes ----------------------- -Chipyard will generate a core for every ``InstantiableTileParams`` object it discovered in the current config. +Wrap Verilog Module with Blackbox (Optional) +-------------------------------------------- + +Since Chipyard uses Scala and Chisel, if the top module of your core is not in Chisel, you will first need to create a Verilog +blackbox for it so that it can be processed by Chipyard. See :ref:`incorporating-verilog-blocks` for instructions. + +Create Parameter Case Classes +----------------------------- + +Chipyard will generate a core for every ``InstantiableTileParams`` object it discovered in the ``TilesLocated(InSubsystem)`` key. This object is derived from``TileParams``, a trait containing the information needed to create a tile. All cores must have their own implementation of ``InstantiableTileParams``, as well as ``CoreParams`` which is passed as a field in ``TileParams``. @@ -41,7 +44,7 @@ need a custom field with similar purposes): val icache: Option[ICacheParams] // Rocket specific: I1 cache option val dcache: Option[DCacheParams] // Rocket specific: D1 cache option val btb: Option[BTBParams] // Rocket specific: BTB / branch predictor option - val hartId: Int // Hart ID: Must be unique within a design config + val hartId: Int // Hart ID: Must be unique within a design config (This MUST be a case class parameter) val beuAddr: Option[BigInt] // Rocket specific: Bus Error Unit for Rocket Core val blockerCtrlAddr: Option[BigInt] // Rocket specific: Bus Blocker for Rocket Core val name: Option[String] // Name of the core @@ -110,110 +113,64 @@ need a custom field with similar purposes): dfmaLatency: Int = 4 // Rocket specific: Fused multiply-add pipeline latency (double precision) ) -Most of the fields here are originally designed for Rocket core and contains some architecture-specific details, but +Most of the fields here are originally designed for the Rocket core and thus contain some implementation-specific details, but many of them are general enough to be useful for other cores. It is strongly recommended to use these fields instead of creating your own custom fields when applicable. +You will also need a ``CanAttachTile`` class to add the tile config into the config system, with the following format: + +.. literalinclude:: ../../generators/chipyard/src/main/scala/example/TutorialTile.scala + :language: scala + :lines: 61-67 + .. note:: Implementations may choose to ignore some fields here or use them in a non-standard way, but using an inaccurate - value may break Chipyard components that rely on them (e.g. inaccurate indication of supported ISA extension will - result in incorrect test suite being generated) as well as any custom module that use them. ALWAYS document any + value may break Chipyard components that rely on them (e.g. an inaccurate indication of supported ISA extension will + result in an incorrect test suite being generated) as well as any custom modules that use them. ALWAYS document any fields you ignore or with altered usage in your core implementation, and if you are implementing other devices that would look up these config values, also document them. "Rocket specific" values are generally safe to ignore, but you should document them if you use them. -Tile Class ----------- +Create Tile Class +----------------- In Chipyard, all Tiles are diplomatically instantiated. In the first phase, diplomatic nodes which specify Tile-to-System interconnects are evaluated, while in the second "Module Implementation" phase, hardware is elaborated. -See :ref:`tilelink_and_diplomacy` for more details. +See :ref:`tilelink_and_diplomacy` for more details. In this step, you will need to implement a tile class for your core. All tile classes implement ``BaseTile`` and will normally implement ``SinksExternalInterrupts`` and ``SourcesExternalNotifications``, which allow the tile to accept external interrupt. A typical tile has the following form: -.. code-block:: scala +.. literalinclude:: ../../generators/chipyard/src/main/scala/example/TutorialTile.scala + :language: scala + :lines: 87-125, 143 - class MyTile( - val myParams: MyTileParams, - crossing: ClockCrossingType, - lookup: LookupByHartIdImpl, - q: Parameters, - logicalTreeNode: LogicalTreeNode) - extends BaseTile(myParams, crossing, lookup, q) - with SinksExternalInterrupts - with SourcesExternalNotifications - { +Connect TileLink Buses +---------------------- - // Private constructor ensures altered LazyModule.p is used implicitly - def this(params: MyTileParams, crossing: RocketCrossingParams, lookup: LookupByHartIdImpl, logicalTreeNode: LogicalTreeNode)(implicit p: Parameters) = - this(params, crossing.crossingType, lookup, p, logicalTreeNode) - - // Require TileLink nodes - val intOutwardNode = IntIdentityNode() - val masterNode = visibilityNode - val slaveNode = TLIdentityNode() - - // Implementation class (See below) - override lazy val module = new MyTileModuleImp(this) - - // Required entry of CPU device in the device tree for interrupt purpose - val cpuDevice: SimpleDevice = new SimpleDevice("cpu", Seq("my-organization,my-cpu", "riscv")) { - override def parent = Some(ResourceAnchors.cpus) - override def describe(resources: ResourceBindings): Description = { - val Description(name, mapping) = super.describe(resources) - Description(name, mapping ++ - cpuProperties ++ - nextLevelCacheProperty ++ - tileProperties) - } - } - - ResourceBinding { - Resource(cpuDevice, "reg").bind(ResourceAddress(hartId)) - } - - // (Connection to bus, interrupt, etc.) - } - -TileLink Connection -------------------- - -Chipyard use TileLink as its onboard bus protocol, and if your core doesn't use TileLink, you will need to convert them +Chipyard use TileLink as its onboard bus protocol. If your core doesn't use TileLink, you will need to insert converters +between the core's memory protocol and TileLink in the Tile module. in the tile class. Below is an example of how to connect a core using AXI4 to the TileLink bus with converters provided by -Chipyards: +Rocket chip: -.. code-block:: scala - - val memoryTap = TLIdentityNode() // Every bus connection should have their own tap node - (tlMasterXbar.node // tlMasterXbar is the bus crossbar to be used when this core / tile is acting as a master; otherwise, use tlSlaveXBar - := memoryTap - := TLBuffer() - := TLFIFOFixer(TLFIFOFixer.all) // fix FIFO ordering - := TLWidthWidget(beatBytes) // reduce size of TL - := AXI4ToTL() // convert to TL - := AXI4UserYanker(Some(2)) // remove user field on AXI interface. need but in reality user intf. not needed - := AXI4Fragmenter() // deal with multi-beat xacts - := memAXI4Node) // The custom node, see below +.. literalinclude:: ../../generators/chipyard/src/main/scala/example/TutorialTile.scala + :language: scala + :lines: 133-142 Remember, you may not need all of these intermediate widgets. See :ref:`diplomatic_widgets` for the meaning of each intermediate widget. If you are using TileLink, then you only need the tap node and the TileLink node used by your components. Chipyard also provides converters for AHB, APB and AXIS, and most of the AXI4 widgets has equivalent widget for these bus protocol; see the source files in ``generators/rocket-chip/src/main/scala/amba`` for more info. -If you are using other bus protocol, you may implement your own converters, using the files in ``generators/rocket-chip/src/main/scala/amba`` +If you are using some other bus protocol, you may implement your own converters, using the files in ``generators/rocket-chip/src/main/scala/amba`` as the template, but it is not recommended unless you are familiar with TileLink. ``memAXI4Node`` is an AXI4 master node and is defined as following in our example: -.. code-block:: scala - - val memAXI4Node = AXI4MasterNode( - Seq(AXI4MasterPortParameters( - masters = Seq(AXI4MasterParameters( - name = portName, - id = IdRange(0, 1 << idBits)))))) +.. literalinclude:: ../../generators/chipyard/src/main/scala/example/TutorialTile.scala + :language: scala + :lines: 126-132 where ``portName`` and ``idBits`` (number of bits to represent a port ID) are the parameter provides by the tile. Make sure to read :ref:`node_types` to check out what type of nodes Chipyard supports and their parameters! @@ -228,8 +185,8 @@ can override the following two functions to control how to buffer the bus reques You can find more information on ``TLBuffer`` in :ref:`diplomatic_widgets`. -Interrupt ---------- +Connect Interrupt +----------------- Chipyard allows a tile to either receive interrupts from other devices or initiate interrupts to notify other cores/devices. In the tile that inherited ``SinksExternalInterrupts``, one can create a ``TileInterrupts`` object (a Chisel bundle) and @@ -258,48 +215,33 @@ from the implementation class: reportCease(could_cease: Option[Bool], quiescenceCycles: Int = 8) // Triggered when the core stop retiring instructions (like clock gating) reportWFI(could_wfi: Option[Bool]) // Triggered when a WFI instruction is executed -Implementation Class --------------------- +Create Implementation Class +--------------------------- -The implementation class is of the following form: +The implementation class for your core is of the following form: -.. code-block:: scala - - class MyTileModuleImp(outer: MyTile) extends BaseTileModuleImp(outer){ - // annotate the parameters - Annotated.params(this, outer.tileParams) - - // TODO: Create the top module of the core and connect it with the ports in "outer" - } +.. literalinclude:: ../../generators/chipyard/src/main/scala/example/TutorialTile.scala + :language: scala + :lines: 145-149, 160 In the body of this class, you can look up any parameters by calling ``p({key})``, where ``{key}`` is the config key of -the value you want to look up. For a list of available keys, see the appendix below. +the value you want to look up. For a list of frequently used keys, see the appendix below. If you create an AXI4 node (or equivalents), you will need to connect them to your core. You can connect a port like this: -.. code-block:: scala +.. literalinclude:: ../../generators/chipyard/src/main/scala/example/TutorialTile.scala + :language: scala + :lines: 151-159 - outer.myAXI4Node.out foreach { case (out, edgeOut) => - // Connect your module IO port to "out" - // The type of "out" here is AXI4Bundle, which is defined in generators/rocket-chip/src/main/scala/amba/axi4/Bundles.scala - // Please refer to this file for the definition of the ports. - // If you are using APB, check APBBundle in generators/rocket-chip/src/main/scala/amba/apb/Bundles.scala - // If you are using AHB, check AHBSlaveBundle or AHBMasterBundle in generators/rocket-chip/src/main/scala/amba/ahb/Bundles.scala - // (choose one depends on the type of AHB node you create) - // If you are using AXIS, check AXISBundle and AXISBundleBits in generators/rocket-chip/src/main/scala/amba/axis/Bundles.scala - } +Create Config Fragments to Integrate the Core +--------------------------------------------- -Integrate the Core ------------------- - -To use your core in a set of config, you would need a config fragment that would create a ``TileParams`` object of your core in +To use your core in a Chipyard config, you would need a config fragment that would create a ``TileParams`` object of your core in the current config. An example of such config will be like this: -.. code-block:: scala - - class WithNMyCores(n: Int, hartidOffset: Int) extends Config((site, here, up) => { - case TilesLocated(InSubsystem) => up(TilesLocated(InSubsystem)) :++ List.tabulate(n)(i => MyTileParams(hartId = i + hartidOffset)) - }) +.. literalinclude:: ../../generators/chipyard/src/main/scala/example/TutorialTile.scala + :language: scala + :lines: 162-179 Chipyard looks up the tile parameters in the field ``TilesLocated(InSubsystem)``, whose type is a list of ``InstantiableTileParams``. This config fragment simply appends new tile parameters to the end of this list. @@ -308,6 +250,9 @@ Now you have finished all the steps to prepare your cores for Chipyard! To gener in :ref:`custom_chisel` to add your project to the build system, then create a config by following the steps in :ref:`hetero_socs_`. You can now run any desired workflow for the new config just as you do for the built-in cores. +If you would like to see how an actual core are integrated into Chipyard, ``generators/ariane/src/main/scala/ArianeTile.scala`` +provides a concrete example of integrating a third party Verilog core Ariane. + Appendix: Common Config Keys ---------------------------- diff --git a/generators/chipyard/src/main/scala/example/TutorialTile.scala b/generators/chipyard/src/main/scala/example/TutorialTile.scala new file mode 100644 index 00000000..12173184 --- /dev/null +++ b/generators/chipyard/src/main/scala/example/TutorialTile.scala @@ -0,0 +1,179 @@ +package chipyard.example + +import chisel3._ +import chisel3.util._ + +import freechips.rocketchip.config._ +import freechips.rocketchip.subsystem._ +import freechips.rocketchip.devices.tilelink._ +import freechips.rocketchip.diplomacy._ +import freechips.rocketchip.diplomaticobjectmodel.logicaltree.{LogicalTreeNode} +import freechips.rocketchip.rocket._ +import freechips.rocketchip.subsystem.{RocketCrossingParams} +import freechips.rocketchip.tilelink._ +import freechips.rocketchip.interrupts._ +import freechips.rocketchip.util._ +import freechips.rocketchip.tile._ +import freechips.rocketchip.amba.axi4._ + +// Example parameter class copied from Ariane, not included in documentation but for compile check only +// If you are here for documentation, DO NOT copy MyCoreParams and MyTileParams directly - always figure +// out what parameters you need before you write the parameter class +case class MyCoreParams( + bootFreqHz: BigInt = BigInt(1700000000), + rasEntries: Int = 4, + btbEntries: Int = 16, + bhtEntries: Int = 16, + enableToFromHostCaching: Boolean = false, +) extends CoreParams { + val useVM: Boolean = true + val useUser: Boolean = true + val useSupervisor: Boolean = false + val useDebug: Boolean = true + val useAtomics: Boolean = true + val useAtomicsOnlyForIO: Boolean = false // copied from Rocket + val useCompressed: Boolean = true + override val useVector: Boolean = false + val useSCIE: Boolean = false + val useRVE: Boolean = false + val mulDiv: Option[MulDivParams] = Some(MulDivParams()) // copied from Rocket + val fpu: Option[FPUParams] = Some(FPUParams()) // copied fma latencies from Rocket + val nLocalInterrupts: Int = 0 + val nPMPs: Int = 0 // TODO: Check + val pmpGranularity: Int = 4 // copied from Rocket + val nBreakpoints: Int = 0 // TODO: Check + val useBPWatch: Boolean = false + val nPerfCounters: Int = 29 + val haveBasicCounters: Boolean = true + val haveFSDirty: Boolean = false + val misaWritable: Boolean = false + val haveCFlush: Boolean = false + val nL2TLBEntries: Int = 512 // copied from Rocket + val mtvecInit: Option[BigInt] = Some(BigInt(0)) // copied from Rocket + val mtvecWritable: Boolean = true // copied from Rocket + val instBits: Int = if (useCompressed) 16 else 32 + val lrscCycles: Int = 80 // copied from Rocket + val decodeWidth: Int = 1 // TODO: Check + val fetchWidth: Int = 1 // TODO: Check + val retireWidth: Int = 2 +} + +case class MyTileAttachParams( + tileParams: MyTileParams, + crossingParams: RocketCrossingParams +) extends CanAttachTile { + type TileType = MyTile + val lookup = PriorityMuxHartIdFromSeq(Seq(tileParams)) +} + +case class MyTileParams( + name: Option[String] = Some("my_tile"), + hartId: Int = 0, + trace: Boolean = false, + val core: MyCoreParams = MyCoreParams() +) extends InstantiableTileParams[MyTile] +{ + val beuAddr: Option[BigInt] = None + val blockerCtrlAddr: Option[BigInt] = None + val btb: Option[BTBParams] = Some(BTBParams()) + val boundaryBuffers: Boolean = false + val dcache: Option[DCacheParams] = Some(DCacheParams()) + val icache: Option[ICacheParams] = Some(ICacheParams()) + def instantiate(crossing: TileCrossingParamsLike, lookup: LookupByHartIdImpl)(implicit p: Parameters): MyTile = { + new MyTile(this, crossing, lookup) + } +} + +class MyTile( + val myParams: MyTileParams, + crossing: ClockCrossingType, + lookup: LookupByHartIdImpl, + q: Parameters) + extends BaseTile(myParams, crossing, lookup, q) + with SinksExternalInterrupts + with SourcesExternalNotifications +{ + + // Private constructor ensures altered LazyModule.p is used implicitly + def this(params: MyTileParams, crossing: TileCrossingParamsLike, lookup: LookupByHartIdImpl)(implicit p: Parameters) = + this(params, crossing.crossingType, lookup, p) + + // Require TileLink nodes + val intOutwardNode = IntIdentityNode() + val masterNode = visibilityNode + val slaveNode = TLIdentityNode() + + // Implementation class (See below) + override lazy val module = new MyTileModuleImp(this) + + // Required entry of CPU device in the device tree for interrupt purpose + val cpuDevice: SimpleDevice = new SimpleDevice("cpu", Seq("my-organization,my-cpu", "riscv")) { + override def parent = Some(ResourceAnchors.cpus) + override def describe(resources: ResourceBindings): Description = { + val Description(name, mapping) = super.describe(resources) + Description(name, mapping ++ + cpuProperties ++ + nextLevelCacheProperty ++ + tileProperties) + } + } + + ResourceBinding { + Resource(cpuDevice, "reg").bind(ResourceAddress(hartId)) + } + + // (Connection to bus, interrupt, etc.) + // # of bits used in TileLink ID for master node. 4 bits can support 16 master nodes, but you can have a longer ID if you need more. + val idBits = 4 + val memAXI4Node = AXI4MasterNode( + Seq(AXI4MasterPortParameters( + masters = Seq(AXI4MasterParameters( + name = "myPortName", + id = IdRange(0, 1 << idBits)))))) + val memoryTap = TLIdentityNode() // Every bus connection should have their own tap node + (tlMasterXbar.node // tlMasterXbar is the bus crossbar to be used when this core / tile is acting as a master; otherwise, use tlSlaveXBar + := memoryTap + := TLBuffer() + := TLFIFOFixer(TLFIFOFixer.all) // fix FIFO ordering + := TLWidthWidget(masterPortBeatBytes) // reduce size of TL + := AXI4ToTL() // convert to TL + := AXI4UserYanker(Some(2)) // remove user field on AXI interface. need but in reality user intf. not needed + := AXI4Fragmenter() // deal with multi-beat xacts + := memAXI4Node) // The custom node, see below +} + +class MyTileModuleImp(outer: MyTile) extends BaseTileModuleImp(outer){ + // annotate the parameters + Annotated.params(this, outer.myParams) + + // TODO: Create the top module of the core and connect it with the ports in "outer" + + outer.memAXI4Node.out foreach { case (out, edgeOut) => + // Connect your module IO port to "out" + // The type of "out" here is AXI4Bundle, which is defined in generators/rocket-chip/src/main/scala/amba/axi4/Bundles.scala + // Please refer to this file for the definition of the ports. + // If you are using APB, check APBBundle in generators/rocket-chip/src/main/scala/amba/apb/Bundles.scala + // If you are using AHB, check AHBSlaveBundle or AHBMasterBundle in generators/rocket-chip/src/main/scala/amba/ahb/Bundles.scala + // (choose one depends on the type of AHB node you create) + // If you are using AXIS, check AXISBundle and AXISBundleBits in generators/rocket-chip/src/main/scala/amba/axis/Bundles.scala + } +} + +class WithNMyCores(n: Int = 1, overrideIdOffset: Option[Int] = None) extends Config((site, here, up) => { + case TilesLocated(InSubsystem) => { + // Calculate the next available hart ID (since hart ID cannot be duplicated) + val prev = up(TilesLocated(InSubsystem), site) + val idOffset = overrideIdOffset.getOrElse(prev.size) + // Create TileAttachParams for every core to be instantiated + (0 until n).map { i => + MyTileAttachParams( + tileParams = MyTileParams(hartId = i + idOffset), + crossingParams = RocketCrossingParams() + ) + } ++ prev + } + // Configurate # of bytes in one memory / IO transaction. For RV64, one load/store instruction can transfer 8 bytes at most. + case SystemBusKey => up(SystemBusKey, site).copy(beatBytes = 8) + // The # of instruction bits. Use maximum # of bits if your core supports both 32 and 64 bits. + case XLen => 64 +}) From 6cb8a60a808d426a111cd470cf360460bbde3cbd Mon Sep 17 00:00:00 2001 From: Zitao Fang Date: Sun, 5 Jul 2020 21:18:31 -0700 Subject: [PATCH 28/42] Remove Key List --- docs/Customization/Custom-Core.rst | 83 ------------------------------ 1 file changed, 83 deletions(-) diff --git a/docs/Customization/Custom-Core.rst b/docs/Customization/Custom-Core.rst index 17b9b125..94d47505 100644 --- a/docs/Customization/Custom-Core.rst +++ b/docs/Customization/Custom-Core.rst @@ -224,9 +224,6 @@ The implementation class for your core is of the following form: :language: scala :lines: 145-149, 160 -In the body of this class, you can look up any parameters by calling ``p({key})``, where ``{key}`` is the config key of -the value you want to look up. For a list of frequently used keys, see the appendix below. - If you create an AXI4 node (or equivalents), you will need to connect them to your core. You can connect a port like this: .. literalinclude:: ../../generators/chipyard/src/main/scala/example/TutorialTile.scala @@ -252,83 +249,3 @@ You can now run any desired workflow for the new config just as you do for the b If you would like to see how an actual core are integrated into Chipyard, ``generators/ariane/src/main/scala/ArianeTile.scala`` provides a concrete example of integrating a third party Verilog core Ariane. - -Appendix: Common Config Keys ----------------------------- - -Chipyard provide a set of keys to store standard parameters. Below are some of the most common key used in core integration. -(Note that internal fields are hidden) - -.. code-block:: scala - - // keys - // Parameters exposed to the top-level design, set based on external requirements, etc. See RISC-V debug specs for more info. - case object DebugModuleKey extends Field[Option[DebugModuleParams]](Some(DebugModuleParams())) - case object BootROMParams extends Field[BootROMParams] // See chipyard boot process tutorial - case object CLINTKey extends Field[Option[CLINTParams]](None) // Core Local Interrupter setting (See SiFive Interrupt Cookbook) - case object PLICKey extends Field[Option[PLICParams]](None) // Platform Level Interrupt Controller setting (See SiFive Interrupt Cookbook) - case object CacheBlockBytes extends Field[Int](64) // # of bytes in a cache block - case object BroadcastKey extends Field(BroadcastParams()) // L2 Cache broadcast setting - case object BankedL2Key extends Field(BankedL2Params()) // L2 Cache memory setting - case object PgLevels extends Field[Int](2) // Page Level of virtual memory - case object ASIdBits extends Field[Int](0) // Max # of bits for Address Space Identifer (See specs) - case object ExtMem extends Field[Option[MemoryPortParams]](None) // External DRAM setting - case object ExtBus extends Field[Option[MasterPortParams]](None) // External (off-chip) output bus setting - case object ExtIn extends Field[Option[SlavePortParams]](None) // External (off-chip) input bus setting - case object MaxHartIdBits extends Field[Int] // Max # of bits used to represent a Hart ID - case object XLen extends Field[Int] // Instruction bits (32 or 64) - case object BuildRoCC extends Field[Seq[Parameters => LazyRoCC]](Nil) // See custom ROCC tutorial - - // Values - case class DebugModuleParams ( - nDMIAddrSize : Int = 7, // Size of the Debug Bus Address - nProgramBufferWords: Int = 16, // Number of 32-bit words for Program Buffer - nAbstractDataWords : Int = 4, // Number of 32-bit words for Abstract Commands - nScratch : Int = 1, // Number of scratch memories used - hasBusMaster : Boolean = false, // Whether or not a bus master should be included - clockGate : Boolean = true, // Use clock gating - maxSupportedSBAccess : Int = 32, // Maximum transaction size supported by System Bus Access logic. - supportQuickAccess : Boolean = false, // Whether or not to support the quick access command. - supportHartArray : Boolean = true, // Whether or not to implement the hart array register (if >1 hart). - nHaltGroups : Int = 1, // Number of halt groups (group of harts that are halted together) - nExtTriggers : Int = 0, // Number of extra triggers - hasHartResets : Boolean = false, // Whether harts can be reseted with debugging system - hasImplicitEbreak : Boolean = false, // There is an additional RO program buffer word containing an ebreak - hasAuthentication : Boolean = false, // Has authentication (to prevent unauthorized users to use debugging system) - crossingHasSafeReset : Boolean = true // Include "safe" logic in Async Crossings so that only one side needs to be reset. - ) - case class CLINTParams( - baseAddress: BigInt = 0x02000000, // Default interrupt handler base address for CLINT - intStages: Int = 0 // # of cycles (stages) interrupts are delayed - ) - case class PLICParams( - baseAddress: BigInt = 0xC000000, // Default interrupt handler base address for PLIC - maxPriorities: Int = 7, // Maximum allowed interrupt priority (cannot be over 7) - intStages: Int = 0, // # of cycles (stages) interrupts are delayed - maxHarts: Int = PLICConsts.maxMaxHarts // Maximum number or hart / core connected to it - ) - case class BroadcastParams( - nTrackers: Int = 4, // # of broadcast tracker - bufferless: Boolean = false // Bufferless broadcast - ) - case class BankedL2Params( - nBanks: Int = 1 // Number of banks in L2 cache - ) - case class MasterPortParams( - base: BigInt, // Base memory address for this port - size: BigInt, // Size of this external memory - beatBytes: Int, // Interface width in bytes - idBits: Int, // # of bits in the port ID - maxXferBytes: Int = 256, // Maximum bytes in one transfer transaction - executable: Boolean = true // If the data from this port can be executed as instruciton - ) - /** Specifies the width of external slave ports */ - case class SlavePortParams( - beatBytes: Int, // Interface width in bytes - idBits: Int, // # of bits in the port ID - sourceBits: Int // # of bits in the source address - ) - case class MemoryPortParams( - master: MasterPortParams, // The memory port setting - nMemoryChannels: Int // Number of memory channel - ) From b55e579c91386f86bcd945412e6d4ac6ba301edc Mon Sep 17 00:00:00 2001 From: Albert Ou Date: Tue, 7 Jul 2020 23:00:14 -0700 Subject: [PATCH 29/42] Override default baud rate for FireChip This avoids target software needing to explicitly set the divisor to match the UART bridge. --- generators/chipyard/src/main/scala/ConfigFragments.scala | 6 +++--- generators/firechip/src/main/scala/TargetConfigs.scala | 7 ++++--- generators/sifive-blocks | 2 +- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/generators/chipyard/src/main/scala/ConfigFragments.scala b/generators/chipyard/src/main/scala/ConfigFragments.scala index da048ff1..dde0e6d8 100644 --- a/generators/chipyard/src/main/scala/ConfigFragments.scala +++ b/generators/chipyard/src/main/scala/ConfigFragments.scala @@ -51,9 +51,9 @@ class WithGPIO extends Config((site, here, up) => { }) // DOC include end: gpio config fragment -class WithUART extends Config((site, here, up) => { +class WithUART(baudrate: BigInt = 115200) extends Config((site, here, up) => { case PeripheryUARTKey => Seq( - UARTParams(address = 0x54000000L, nTxEntries = 256, nRxEntries = 256)) + UARTParams(address = 0x54000000L, nTxEntries = 256, nRxEntries = 256, initBaudRate = baudrate)) }) class WithSPIFlash(size: BigInt = 0x10000000) extends Config((site, here, up) => { @@ -143,4 +143,4 @@ class WithHwachaTest extends Config((site, here, up) => { suiteHelper.addSuite(hwachaBmarks) "SRC_EXTENSION = $(base_dir)/hwacha/$(src_path)/*.scala" + "\nDISASM_EXTENSION = --extension=hwacha" } -}) \ No newline at end of file +}) diff --git a/generators/firechip/src/main/scala/TargetConfigs.scala b/generators/firechip/src/main/scala/TargetConfigs.scala index 2828580a..8aef9f8c 100644 --- a/generators/firechip/src/main/scala/TargetConfigs.scala +++ b/generators/firechip/src/main/scala/TargetConfigs.scala @@ -69,7 +69,8 @@ class WithNVDLASmall extends nvidia.blocks.dla.WithNVDLA("small") class WithFireSimConfigTweaks extends Config( // Required*: When using FireSim-as-top to provide a correct path to the target bootrom source new WithBootROM ++ - // Optional*: Removing this will require target-software changes to properly capture UART output + // Optional*: Removing this will require adjusting the UART baud rate and + // potential target-software changes to properly capture UART output new WithPeripheryBusFrequency(BigInt(3200000000L)) ++ // Required: Existing FAME-1 transform cannot handle black-box clock gates new WithoutClockGating ++ @@ -85,8 +86,8 @@ class WithFireSimConfigTweaks extends Config( new testchipip.WithTSI ++ // Optional: Removing this will require using an initramfs under linux new testchipip.WithBlockDevice ++ - // Required*: - new chipyard.config.WithUART + // Required*: Scale default baud rate with periphery bus frequency + new chipyard.config.WithUART(BigInt(3686400L)) ) /******************************************************************************* diff --git a/generators/sifive-blocks b/generators/sifive-blocks index c1dee823..c240e629 160000 --- a/generators/sifive-blocks +++ b/generators/sifive-blocks @@ -1 +1 @@ -Subproject commit c1dee8234c23c8fc454108e59ecba20987f95cde +Subproject commit c240e629e2fc111cbb12e4fe707be898b5204984 From 763ba42b4c35915d1824b662fe73976697b0662b Mon Sep 17 00:00:00 2001 From: Albert Ou Date: Wed, 8 Jul 2020 12:36:09 -0700 Subject: [PATCH 30/42] Bump testchipip for FDT alignment and minLatency fixes --- generators/testchipip | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/generators/testchipip b/generators/testchipip index 29eb87c9..8b5c89a5 160000 --- a/generators/testchipip +++ b/generators/testchipip @@ -1 +1 @@ -Subproject commit 29eb87c938a2106249b85e3b3dffd00046f5077c +Subproject commit 8b5c89a5f7120e64a7ac5ce5210165426a58f3de From 9ad9d00a232ec38dc19269b61df2a5e0151dad8a Mon Sep 17 00:00:00 2001 From: Zitao Fang Date: Wed, 8 Jul 2020 16:02:31 -0700 Subject: [PATCH 31/42] Second revision --- docs/Customization/Custom-Core.rst | 66 ++++++++++++------- .../src/main/scala/example/TutorialTile.scala | 22 ++++++- 2 files changed, 62 insertions(+), 26 deletions(-) diff --git a/docs/Customization/Custom-Core.rst b/docs/Customization/Custom-Core.rst index 94d47505..9a2249ba 100644 --- a/docs/Customization/Custom-Core.rst +++ b/docs/Customization/Custom-Core.rst @@ -121,7 +121,8 @@ You will also need a ``CanAttachTile`` class to add the tile config into the con .. literalinclude:: ../../generators/chipyard/src/main/scala/example/TutorialTile.scala :language: scala - :lines: 61-67 + :start-after: DOC include start: CanAttachTile + :end-before: DOC include end: CanAttachTile .. note:: @@ -137,14 +138,17 @@ Create Tile Class In Chipyard, all Tiles are diplomatically instantiated. In the first phase, diplomatic nodes which specify Tile-to-System interconnects are evaluated, while in the second "Module Implementation" phase, hardware is elaborated. -See :ref:`tilelink_and_diplomacy` for more details. In this step, you will need to implement a tile class for your core. +See :ref:`tilelink_and_diplomacy` for more details. In this step, you will need to implement a tile class for your core, +which specifies the constraints on the core's parameters and the connections with other diplomatic nodes. This class +usually contains Diplomacy/TileLink code only, and Chisel RTL code should not go here. All tile classes implement ``BaseTile`` and will normally implement ``SinksExternalInterrupts`` and ``SourcesExternalNotifications``, which allow the tile to accept external interrupt. A typical tile has the following form: .. literalinclude:: ../../generators/chipyard/src/main/scala/example/TutorialTile.scala :language: scala - :lines: 87-125, 143 + :start-after: DOC include start: Tile class + :end-before: DOC include end: Tile class Connect TileLink Buses ---------------------- @@ -156,7 +160,8 @@ Rocket chip: .. literalinclude:: ../../generators/chipyard/src/main/scala/example/TutorialTile.scala :language: scala - :lines: 133-142 + :start-after: DOC include start: AXI4 convert + :end-before: DOC include end: AXI4 convert Remember, you may not need all of these intermediate widgets. See :ref:`diplomatic_widgets` for the meaning of each intermediate widget. If you are using TileLink, then you only need the tap node and the TileLink node used by your components. Chipyard also @@ -170,7 +175,8 @@ as the template, but it is not recommended unless you are familiar with TileLink .. literalinclude:: ../../generators/chipyard/src/main/scala/example/TutorialTile.scala :language: scala - :lines: 126-132 + :start-after: DOC include start: AXI4 node + :end-before: DOC include end: AXI4 node where ``portName`` and ``idBits`` (number of bits to represent a port ID) are the parameter provides by the tile. Make sure to read :ref:`node_types` to check out what type of nodes Chipyard supports and their parameters! @@ -185,12 +191,36 @@ can override the following two functions to control how to buffer the bus reques You can find more information on ``TLBuffer`` in :ref:`diplomatic_widgets`. +Create Implementation Class +--------------------------- + +The implementation class contains the parameterized, actual hardware that depends on the values resolved by the Diplomacy +framework according to the info provided in the Tile class. This class will normally contains Chisel RTL codes, and if your +core is in Verilog, you will need to put the black box class you created in the first step here and connect it with the buses +and other components. No Diplomacy/TileLink code should be in this class; you should only connect the IO signals in TileLink +interfaces or other diplomatically defined components, which are located in the tile class. + +The implementation class for your core is of the following form: + +.. literalinclude:: ../../generators/chipyard/src/main/scala/example/TutorialTile.scala + :language: scala + :start-after: DOC include start: Implementation class + :end-before: DOC include end: Implementation class + +If you create an AXI4 node (or equivalents), you will need to connect them to your core. You can connect a port like this: + +.. literalinclude:: ../../generators/chipyard/src/main/scala/example/TutorialTile.scala + :language: scala + :start-after: DOC include start: AXI4 connect + :end-before: DOC include end: AXI4 connect + Connect Interrupt ----------------- Chipyard allows a tile to either receive interrupts from other devices or initiate interrupts to notify other cores/devices. In the tile that inherited ``SinksExternalInterrupts``, one can create a ``TileInterrupts`` object (a Chisel bundle) and -call ``decodeCoreInterrupts`` with the object as the argument. You can then read the interrupt bits from the object. +call ``decodeCoreInterrupts`` with the object as the argument. Note that you should call this function in the implementation +class since it returns a Chisel bundle used by RTL code. You can then read the interrupt bits from the object. The definition of ``TileInterrupts`` is .. code-block:: scala @@ -204,7 +234,6 @@ The definition of ``TileInterrupts`` is val lip = Vec(coreParams.nLocalInterrupts, Bool()) // Local interrupts } -This function should be in the implementation class since it involves hardware generation. Also, the tile can also notify other cores or devices for some events by calling following functions in ``SourcesExternalNotifications`` from the implementation class: @@ -215,21 +244,6 @@ from the implementation class: reportCease(could_cease: Option[Bool], quiescenceCycles: Int = 8) // Triggered when the core stop retiring instructions (like clock gating) reportWFI(could_wfi: Option[Bool]) // Triggered when a WFI instruction is executed -Create Implementation Class ---------------------------- - -The implementation class for your core is of the following form: - -.. literalinclude:: ../../generators/chipyard/src/main/scala/example/TutorialTile.scala - :language: scala - :lines: 145-149, 160 - -If you create an AXI4 node (or equivalents), you will need to connect them to your core. You can connect a port like this: - -.. literalinclude:: ../../generators/chipyard/src/main/scala/example/TutorialTile.scala - :language: scala - :lines: 151-159 - Create Config Fragments to Integrate the Core --------------------------------------------- @@ -238,7 +252,8 @@ the current config. An example of such config will be like this: .. literalinclude:: ../../generators/chipyard/src/main/scala/example/TutorialTile.scala :language: scala - :lines: 162-179 + :start-after: DOC include start: Config fragment + :end-before: DOC include end: Config fragment Chipyard looks up the tile parameters in the field ``TilesLocated(InSubsystem)``, whose type is a list of ``InstantiableTileParams``. This config fragment simply appends new tile parameters to the end of this list. @@ -247,5 +262,6 @@ Now you have finished all the steps to prepare your cores for Chipyard! To gener in :ref:`custom_chisel` to add your project to the build system, then create a config by following the steps in :ref:`hetero_socs_`. You can now run any desired workflow for the new config just as you do for the built-in cores. -If you would like to see how an actual core are integrated into Chipyard, ``generators/ariane/src/main/scala/ArianeTile.scala`` -provides a concrete example of integrating a third party Verilog core Ariane. +If you would like to see an example of a complete third-party Verilog core integrated into Chipyard, ``generators/ariane/src/main/scala/ArianeTile.scala`` +provides a concrete example of the Ariane core. Note that this particular example includes additional nuances with respect to the interaction of the AXI +interface with the memory coherency system. \ No newline at end of file diff --git a/generators/chipyard/src/main/scala/example/TutorialTile.scala b/generators/chipyard/src/main/scala/example/TutorialTile.scala index 12173184..41f79892 100644 --- a/generators/chipyard/src/main/scala/example/TutorialTile.scala +++ b/generators/chipyard/src/main/scala/example/TutorialTile.scala @@ -58,6 +58,7 @@ case class MyCoreParams( val retireWidth: Int = 2 } +// DOC include start: CanAttachTile case class MyTileAttachParams( tileParams: MyTileParams, crossingParams: RocketCrossingParams @@ -65,6 +66,7 @@ case class MyTileAttachParams( type TileType = MyTile val lookup = PriorityMuxHartIdFromSeq(Seq(tileParams)) } +// DOC include end: CanAttachTile case class MyTileParams( name: Option[String] = Some("my_tile"), @@ -84,6 +86,7 @@ case class MyTileParams( } } +// DOC include start: Tile class class MyTile( val myParams: MyTileParams, crossing: ClockCrossingType, @@ -123,6 +126,10 @@ class MyTile( } // (Connection to bus, interrupt, etc.) +// } + // DOC include end: Tile class + + // DOC include start: AXI4 node // # of bits used in TileLink ID for master node. 4 bits can support 16 master nodes, but you can have a longer ID if you need more. val idBits = 4 val memAXI4Node = AXI4MasterNode( @@ -131,6 +138,9 @@ class MyTile( name = "myPortName", id = IdRange(0, 1 << idBits)))))) val memoryTap = TLIdentityNode() // Every bus connection should have their own tap node + // DOC include end: AXI4 node + + // DOC include start: AXI4 convert (tlMasterXbar.node // tlMasterXbar is the bus crossbar to be used when this core / tile is acting as a master; otherwise, use tlSlaveXBar := memoryTap := TLBuffer() @@ -140,14 +150,20 @@ class MyTile( := AXI4UserYanker(Some(2)) // remove user field on AXI interface. need but in reality user intf. not needed := AXI4Fragmenter() // deal with multi-beat xacts := memAXI4Node) // The custom node, see below + // DOC include end: AXI4 convert + } +// DOC include start: Implementation class class MyTileModuleImp(outer: MyTile) extends BaseTileModuleImp(outer){ // annotate the parameters Annotated.params(this, outer.myParams) - // TODO: Create the top module of the core and connect it with the ports in "outer" + // TODO: Create the top module of the core and connect it with the ports in "outer" } +//} + // DOC include end: Implementation class + // DOC include start: AXI4 connect outer.memAXI4Node.out foreach { case (out, edgeOut) => // Connect your module IO port to "out" // The type of "out" here is AXI4Bundle, which is defined in generators/rocket-chip/src/main/scala/amba/axi4/Bundles.scala @@ -157,8 +173,11 @@ class MyTileModuleImp(outer: MyTile) extends BaseTileModuleImp(outer){ // (choose one depends on the type of AHB node you create) // If you are using AXIS, check AXISBundle and AXISBundleBits in generators/rocket-chip/src/main/scala/amba/axis/Bundles.scala } + // DOC include end: AXI4 connect + } +// DOC include start: Config fragment class WithNMyCores(n: Int = 1, overrideIdOffset: Option[Int] = None) extends Config((site, here, up) => { case TilesLocated(InSubsystem) => { // Calculate the next available hart ID (since hart ID cannot be duplicated) @@ -177,3 +196,4 @@ class WithNMyCores(n: Int = 1, overrideIdOffset: Option[Int] = None) extends Con // The # of instruction bits. Use maximum # of bits if your core supports both 32 and 64 bits. case XLen => 64 }) +// DOC include end: Config fragment From 11c87777fe7ce8dba0854d2bcc65321f8e0d27a7 Mon Sep 17 00:00:00 2001 From: Jerry Zhao Date: Thu, 9 Jul 2020 11:29:58 -0700 Subject: [PATCH 32/42] Remove BOOM debug print --- generators/chipyard/src/main/scala/config/BoomConfigs.scala | 2 -- 1 file changed, 2 deletions(-) diff --git a/generators/chipyard/src/main/scala/config/BoomConfigs.scala b/generators/chipyard/src/main/scala/config/BoomConfigs.scala index 1f41c252..8b7cd31e 100644 --- a/generators/chipyard/src/main/scala/config/BoomConfigs.scala +++ b/generators/chipyard/src/main/scala/config/BoomConfigs.scala @@ -19,7 +19,6 @@ class LargeBoomConfig extends Config( new chipyard.config.AbstractConfig) class MegaBoomConfig extends Config( - new boom.common.WithBoomBranchPrintf ++ new boom.common.WithNMegaBooms(1) ++ // mega boom config new chipyard.config.AbstractConfig) @@ -43,4 +42,3 @@ class DromajoBoomConfig extends Config( new chipyard.config.WithTraceIO ++ // enable the traceio new boom.common.WithNSmallBooms(1) ++ new chipyard.config.AbstractConfig) - From 8124ce3df1483b5a1321f60005bf86c0c296cec4 Mon Sep 17 00:00:00 2001 From: Jerry Zhao Date: Thu, 9 Jul 2020 12:38:21 -0700 Subject: [PATCH 33/42] Add FIRRTL_LOGLEVEL variable --- variables.mk | 2 ++ 1 file changed, 2 insertions(+) diff --git a/variables.mk b/variables.mk index 48da498e..e6de6ca0 100644 --- a/variables.mk +++ b/variables.mk @@ -152,6 +152,8 @@ define run_scala_main endef endif +FIRRTL_LOGLEVEL ?= error + ######################################################################################### # output directory for tests ######################################################################################### From 2196a621c67d1cc598116ddfd498719c57d4f17a Mon Sep 17 00:00:00 2001 From: Jerry Zhao Date: Thu, 9 Jul 2020 12:39:17 -0700 Subject: [PATCH 34/42] Pass FIRRTL_LOGLEVEL to GenerateTopAndHarness --- common.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common.mk b/common.mk index 62e4399e..71f4440c 100644 --- a/common.mk +++ b/common.mk @@ -104,7 +104,7 @@ $(TOP_TARGETS) $(HARNESS_TARGETS): firrtl_temp @echo "" > /dev/null firrtl_temp: $(FIRRTL_FILE) $(ANNO_FILE) $(VLOG_SOURCES) - $(call run_scala_main,tapeout,barstools.tapeout.transforms.GenerateTopAndHarness,-o $(TOP_FILE) -tho $(HARNESS_FILE) -i $(FIRRTL_FILE) --syn-top $(TOP) --harness-top $(VLOG_MODEL) -faf $(ANNO_FILE) -tsaof $(TOP_ANNO) -tdf $(sim_top_blackboxes) -tsf $(TOP_FIR) -thaof $(HARNESS_ANNO) -hdf $(sim_harness_blackboxes) -thf $(HARNESS_FIR) $(REPL_SEQ_MEM) $(HARNESS_CONF_FLAGS) -td $(build_dir)) && touch $(sim_top_blackboxes) $(sim_harness_blackboxes) + $(call run_scala_main,tapeout,barstools.tapeout.transforms.GenerateTopAndHarness,-o $(TOP_FILE) -tho $(HARNESS_FILE) -i $(FIRRTL_FILE) --syn-top $(TOP) --harness-top $(VLOG_MODEL) -faf $(ANNO_FILE) -tsaof $(TOP_ANNO) -tdf $(sim_top_blackboxes) -tsf $(TOP_FIR) -thaof $(HARNESS_ANNO) -hdf $(sim_harness_blackboxes) -thf $(HARNESS_FIR) $(REPL_SEQ_MEM) $(HARNESS_CONF_FLAGS) -td $(build_dir) -ll $(FIRRTL_LOGLEVEL)) && touch $(sim_top_blackboxes) $(sim_harness_blackboxes) # DOC include end: FirrtlCompiler # This file is for simulation only. VLSI flows should replace this file with one containing hard SRAMs From ced7ea634cc2eae5a8045a20ce81c177f347c0b3 Mon Sep 17 00:00:00 2001 From: Zitao Fang Date: Sun, 12 Jul 2020 01:08:13 -0700 Subject: [PATCH 35/42] 3rd Revision --- docs/Customization/Custom-Core.rst | 41 +++++++++++-------- .../src/main/scala/example/TutorialTile.scala | 4 +- 2 files changed, 25 insertions(+), 20 deletions(-) diff --git a/docs/Customization/Custom-Core.rst b/docs/Customization/Custom-Core.rst index 9a2249ba..d6a19f04 100644 --- a/docs/Customization/Custom-Core.rst +++ b/docs/Customization/Custom-Core.rst @@ -3,8 +3,8 @@ Adding a custom core ==================== -You may want to integrate a custom RISC-V core into the Chipyard framework. This documentation page provides a step-to-step -instruction on how to achieve this. +You may want to integrate a custom RISC-V core into the Chipyard framework. This documentation page provides step-by-step +instructions on how to achieve this. .. note:: @@ -24,18 +24,18 @@ Chipyard will generate a core for every ``InstantiableTileParams`` object it dis This object is derived from``TileParams``, a trait containing the information needed to create a tile. All cores must have their own implementation of ``InstantiableTileParams``, as well as ``CoreParams`` which is passed as a field in ``TileParams``. -``TileParams`` holds the parameters for the tile, which are the same for every generated core, while ``CoreParams`` -contains the parameters for individual cores. They must be implemented as case classes with fields that can be overridden by +``TileParams`` holds the parameters for the tile, which include parameters for all components in the tile (e.g. +core, cache, MMU, etc.), while ``CoreParams`` contains parameters specific to the core on the tile. +They must be implemented as case classes with fields that can be overridden by other config fragments as the constructor parameters. See the appendix at the bottom of the page for a list of variable to be implemented. You can also add custom fields to them, but standard fields should always be preferred. -``InstantiableTileParams[TileType]`` holds the constructor of ``TileType`` on top of the fields of ``TileParams``. +``InstantiableTileParams[TileType]`` holds the constructor of ``TileType`` on top of the fields of ``TileParams``, +where ``TileType`` is the tile class (see the next section). All custom cores will also need to implement ``instantiate()`` in their tile parameter class to return a new instance of the tile class ``TileType``. -``TileParams``, ``InstantiableTileParams[TileType]`` and ``CoreParams`` contains the following fields (you may ignore -any fields marked "Rocket specific" and use their default values, although it is recommended to use them if you -need a custom field with similar purposes): +``TileParams``, ``InstantiableTileParams[TileType]`` and ``CoreParams`` contains the following fields: .. code-block:: scala @@ -113,9 +113,11 @@ need a custom field with similar purposes): dfmaLatency: Int = 4 // Rocket specific: Fused multiply-add pipeline latency (double precision) ) -Most of the fields here are originally designed for the Rocket core and thus contain some implementation-specific details, but -many of them are general enough to be useful for other cores. It is strongly recommended to use these fields instead -of creating your own custom fields when applicable. +Most of the fields here (marked "Rocket spcific") are originally designed for the Rocket core and thus contain some +implementation-specific details, but many of them are general enough to be useful for other cores. You may ignore +any fields marked "Rocket specific" and use their default values; however, if you need to store additional information +with meaning or usage similar to these "Rocket specific" fields, it is recommended to use these fields instead of +creating your own custom fields. You will also need a ``CanAttachTile`` class to add the tile config into the config system, with the following format: @@ -124,6 +126,9 @@ You will also need a ``CanAttachTile`` class to add the tile config into the con :start-after: DOC include start: CanAttachTile :end-before: DOC include end: CanAttachTile +During elaboration, Chipyard will look for subclasses of ``CanAttachTile`` in the config system and instantiate a tile +from the parameters in this class for every such class it found. + .. note:: Implementations may choose to ignore some fields here or use them in a non-standard way, but using an inaccurate @@ -153,8 +158,8 @@ which allow the tile to accept external interrupt. A typical tile has the follow Connect TileLink Buses ---------------------- -Chipyard use TileLink as its onboard bus protocol. If your core doesn't use TileLink, you will need to insert converters -between the core's memory protocol and TileLink in the Tile module. +Chipyard uses TileLink as its onboard bus protocol. If your core doesn't use TileLink, you will need to insert converters +between the core's memory protocol and TileLink within the Tile module. in the tile class. Below is an example of how to connect a core using AXI4 to the TileLink bus with converters provided by Rocket chip: @@ -195,8 +200,8 @@ Create Implementation Class --------------------------- The implementation class contains the parameterized, actual hardware that depends on the values resolved by the Diplomacy -framework according to the info provided in the Tile class. This class will normally contains Chisel RTL codes, and if your -core is in Verilog, you will need to put the black box class you created in the first step here and connect it with the buses +framework according to the info provided in the Tile class. This class will normally contains Chisel RTL code. If your +core is in Verilog, you will need to instantiate the black box class that wraps your Verilog implementation and connect it with the buses and other components. No Diplomacy/TileLink code should be in this class; you should only connect the IO signals in TileLink interfaces or other diplomatically defined components, which are located in the tile class. @@ -247,7 +252,7 @@ from the implementation class: Create Config Fragments to Integrate the Core --------------------------------------------- -To use your core in a Chipyard config, you would need a config fragment that would create a ``TileParams`` object of your core in +To use your core in a Chipyard config, you will need a config fragment that will create a ``TileParams`` object of your core in the current config. An example of such config will be like this: .. literalinclude:: ../../generators/chipyard/src/main/scala/example/TutorialTile.scala @@ -260,8 +265,8 @@ This config fragment simply appends new tile parameters to the end of this list. Now you have finished all the steps to prepare your cores for Chipyard! To generate the custom core, simply follow the instructions in :ref:`custom_chisel` to add your project to the build system, then create a config by following the steps in :ref:`hetero_socs_`. -You can now run any desired workflow for the new config just as you do for the built-in cores. +You can now run most desired workflows for the new config just as you would for the built-in cores (depending on the functionality your core supports). If you would like to see an example of a complete third-party Verilog core integrated into Chipyard, ``generators/ariane/src/main/scala/ArianeTile.scala`` provides a concrete example of the Ariane core. Note that this particular example includes additional nuances with respect to the interaction of the AXI -interface with the memory coherency system. \ No newline at end of file +interface with the memory coherency system. diff --git a/generators/chipyard/src/main/scala/example/TutorialTile.scala b/generators/chipyard/src/main/scala/example/TutorialTile.scala index 41f79892..75ff1e5b 100644 --- a/generators/chipyard/src/main/scala/example/TutorialTile.scala +++ b/generators/chipyard/src/main/scala/example/TutorialTile.scala @@ -125,7 +125,7 @@ class MyTile( Resource(cpuDevice, "reg").bind(ResourceAddress(hartId)) } - // (Connection to bus, interrupt, etc.) + // TODO: Create TileLink nodes and connections here. // } // DOC include end: Tile class @@ -159,7 +159,7 @@ class MyTileModuleImp(outer: MyTile) extends BaseTileModuleImp(outer){ // annotate the parameters Annotated.params(this, outer.myParams) - // TODO: Create the top module of the core and connect it with the ports in "outer" } + // TODO: Create the top module of the core and connect it with the ports in "outer" //} // DOC include end: Implementation class From 14399e88b3fb7c048244c93d53c6600129f5c500 Mon Sep 17 00:00:00 2001 From: Zitao Fang Date: Sun, 12 Jul 2020 01:23:34 -0700 Subject: [PATCH 36/42] Minor change --- docs/Customization/Custom-Core.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/Customization/Custom-Core.rst b/docs/Customization/Custom-Core.rst index d6a19f04..16d19f27 100644 --- a/docs/Customization/Custom-Core.rst +++ b/docs/Customization/Custom-Core.rst @@ -225,7 +225,7 @@ Connect Interrupt Chipyard allows a tile to either receive interrupts from other devices or initiate interrupts to notify other cores/devices. In the tile that inherited ``SinksExternalInterrupts``, one can create a ``TileInterrupts`` object (a Chisel bundle) and call ``decodeCoreInterrupts`` with the object as the argument. Note that you should call this function in the implementation -class since it returns a Chisel bundle used by RTL code. You can then read the interrupt bits from the object. +class since it returns a Chisel bundle used by RTL code. You can then read the interrupt bits from the resulting object. The definition of ``TileInterrupts`` is .. code-block:: scala From 7ea464dc906eb629db1df7deb67ca9641ce01298 Mon Sep 17 00:00:00 2001 From: Zitao Fang Date: Tue, 14 Jul 2020 12:49:36 -0700 Subject: [PATCH 37/42] 4th revision --- docs/Customization/Custom-Core.rst | 26 ++++++++++++++----- .../src/main/scala/example/TutorialTile.scala | 25 ++++++++++++++++++ 2 files changed, 45 insertions(+), 6 deletions(-) diff --git a/docs/Customization/Custom-Core.rst b/docs/Customization/Custom-Core.rst index 16d19f27..4a7f57f1 100644 --- a/docs/Customization/Custom-Core.rst +++ b/docs/Customization/Custom-Core.rst @@ -224,9 +224,9 @@ Connect Interrupt Chipyard allows a tile to either receive interrupts from other devices or initiate interrupts to notify other cores/devices. In the tile that inherited ``SinksExternalInterrupts``, one can create a ``TileInterrupts`` object (a Chisel bundle) and -call ``decodeCoreInterrupts`` with the object as the argument. Note that you should call this function in the implementation -class since it returns a Chisel bundle used by RTL code. You can then read the interrupt bits from the resulting object. -The definition of ``TileInterrupts`` is +call ``decodeCoreInterrupts()`` with the object as the argument. Note that you should call this function in the implementation +class since it returns a Chisel bundle used by RTL code. You can then read the interrupt bits from the ``TileInterrupts`` bundle +we create above. The definition of ``TileInterrupts`` is .. code-block:: scala @@ -239,15 +239,29 @@ The definition of ``TileInterrupts`` is val lip = Vec(coreParams.nLocalInterrupts, Bool()) // Local interrupts } +Here is an example on how to connect these signals in the implementation class: + +.. literalinclude:: ../../generators/chipyard/src/main/scala/example/TutorialTile.scala + :language: scala + :start-after: DOC include start: connect interrupt + :end-before: DOC include end: connect interrupt + Also, the tile can also notify other cores or devices for some events by calling following functions in ``SourcesExternalNotifications`` from the implementation class: .. code-block:: scala def reportHalt(could_halt: Option[Bool]) // Triggered when there is an unrecoverable hardware error (halt the machine) - def reportHalt(errors: Seq[CanHaveErrors]) // Varient for standard error bundle (used only by cache when there's an ECC error) - reportCease(could_cease: Option[Bool], quiescenceCycles: Int = 8) // Triggered when the core stop retiring instructions (like clock gating) - reportWFI(could_wfi: Option[Bool]) // Triggered when a WFI instruction is executed + def reportHalt(errors: Seq[CanHaveErrors]) // Varient for standard error bundle (Rocket specific: used only by cache when there's an ECC error) + def reportCease(could_cease: Option[Bool], quiescenceCycles: Int = 8) // Triggered when the core stop retiring instructions (like clock gating) + def reportWFI(could_wfi: Option[Bool]) // Triggered when a WFI instruction is executed + +Here is an example on how to use these functions to raise interrupt. + +.. literalinclude:: ../../generators/chipyard/src/main/scala/example/TutorialTile.scala + :language: scala + :start-after: DOC include start: raise interrupt + :end-before: DOC include end: raise interrupt Create Config Fragments to Integrate the Core --------------------------------------------- diff --git a/generators/chipyard/src/main/scala/example/TutorialTile.scala b/generators/chipyard/src/main/scala/example/TutorialTile.scala index 75ff1e5b..c8f71b85 100644 --- a/generators/chipyard/src/main/scala/example/TutorialTile.scala +++ b/generators/chipyard/src/main/scala/example/TutorialTile.scala @@ -163,6 +163,31 @@ class MyTileModuleImp(outer: MyTile) extends BaseTileModuleImp(outer){ //} // DOC include end: Implementation class + // DOC include start: connect interrupt + // For example, our core support debug interrupt and machine-level interrupt, and suppose the following two signals + // are the interrupt inputs to the core. (DO NOT COPY this code - if your core treat each type of interrupt differently, + // you need to connect them to different interrupt ports of your core) + val debug_i = Wire(Bool()) + val mtip_i = Wire(Bool()) + // We create a bundle here and decode the interrupt. + val int_bundle = new TileInterrupts() + outer.decodeCoreInterrupts(int_bundle) + debug_i := int_bundle.debug + mtip_i := int_bundle.meip & int_bundle.msip & int_bundle.mtip + // DOC include end: connect interrupt + + // DOC include start: raise interrupt + // This is a demo. You should call these function according to your core + // Suppose that the following signal is from the decoder indicating a WFI instruction is received. + val wfi_o = Wire(Bool()) + outer.reportWFI(Some(wfi_o)) + // Suppose that the following signal indicate an unreconverable hardware error. + val halt_o = Wire(Bool()) + outer.reportHalt(Some(halt_o)) + // Suppose that our core never stall for a long time / stop retiring. Use None to indicate that this interrupt never fires. + outer.reportCease(None) + // DOC include end: raise interrupt + // DOC include start: AXI4 connect outer.memAXI4Node.out foreach { case (out, edgeOut) => // Connect your module IO port to "out" From 9fbc0a5bea7fe7f1b20a46389b18c9e71ee78f4e Mon Sep 17 00:00:00 2001 From: Zitao Fang Date: Wed, 15 Jul 2020 11:08:36 -0700 Subject: [PATCH 38/42] Add links --- docs/Customization/Custom-Core.rst | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/docs/Customization/Custom-Core.rst b/docs/Customization/Custom-Core.rst index 4a7f57f1..3d6a6393 100644 --- a/docs/Customization/Custom-Core.rst +++ b/docs/Customization/Custom-Core.rst @@ -39,6 +39,7 @@ of the tile class ``TileType``. .. code-block:: scala + // The two classes below can be found in https://github.com/chipsalliance/rocket-chip/blob/master/src/main/scala/tile/BaseTile.scala. trait TileParams { val core: CoreParams // Core parameters (see below) val icache: Option[ICacheParams] // Rocket specific: I1 cache option @@ -55,6 +56,7 @@ of the tile class ``TileType``. (implicit p: Parameters): TileType } + // This class can be found in https://github.com/chipsalliance/rocket-chip/blob/master/src/main/scala/tile/Core.scala. trait CoreParams { val bootFreqHz: BigInt // Frequency val useVM: Boolean // Support virtual memory @@ -105,6 +107,7 @@ of the tile class ``TileType``. def vMemDataBits: Int = 0 } + // This class can be found in https://github.com/chipsalliance/rocket-chip/blob/master/src/main/scala/tile/FPU.scala. case class FPUParams( minFLen: Int = 32, // Minimum floating point length (no need to change) fLen: Int = 64, // Maximum floating point length, use 32 if only single precision is supported @@ -191,6 +194,9 @@ can override the following two functions to control how to buffer the bus reques .. code-block:: scala + // This two functions can be found in https://github.com/chipsalliance/rocket-chip/blob/master/src/main/scala/tile/BaseTile.scala, + // in the class "BaseTile". + // By default, their value is "TLBuffer(BufferParams.none)". protected def makeMasterBoundaryBuffers(implicit p: Parameters): TLBuffer protected def makeSlaveBoundaryBuffers(implicit p: Parameters): TLBuffer @@ -230,6 +236,7 @@ we create above. The definition of ``TileInterrupts`` is .. code-block:: scala + // This class can be found in https://github.com/chipsalliance/rocket-chip/blob/master/src/main/scala/tile/Interrupts.scala. class TileInterrupts(implicit p: Parameters) extends CoreBundle()(p) { val debug = Bool() // debug interrupt val mtip = Bool() // Machine level timer interrupt @@ -251,6 +258,8 @@ from the implementation class: .. code-block:: scala + // These functions can be found in https://github.com/chipsalliance/rocket-chip/blob/master/src/main/scala/tile/Interrupts.scala, + // in the trait "SourcesExternalNotifications". def reportHalt(could_halt: Option[Bool]) // Triggered when there is an unrecoverable hardware error (halt the machine) def reportHalt(errors: Seq[CanHaveErrors]) // Varient for standard error bundle (Rocket specific: used only by cache when there's an ECC error) def reportCease(could_cease: Option[Bool], quiescenceCycles: Int = 8) // Triggered when the core stop retiring instructions (like clock gating) From fddf2181471a1d227f75c592e394ec0bc39cc6c7 Mon Sep 17 00:00:00 2001 From: Zitao Fang Date: Thu, 16 Jul 2020 15:39:07 -0700 Subject: [PATCH 39/42] 5th revision --- .../src/main/scala/example/TutorialTile.scala | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/generators/chipyard/src/main/scala/example/TutorialTile.scala b/generators/chipyard/src/main/scala/example/TutorialTile.scala index c8f71b85..1f58e5e4 100644 --- a/generators/chipyard/src/main/scala/example/TutorialTile.scala +++ b/generators/chipyard/src/main/scala/example/TutorialTile.scala @@ -126,7 +126,6 @@ class MyTile( } // TODO: Create TileLink nodes and connections here. -// } // DOC include end: Tile class // DOC include start: AXI4 node @@ -160,7 +159,20 @@ class MyTileModuleImp(outer: MyTile) extends BaseTileModuleImp(outer){ Annotated.params(this, outer.myParams) // TODO: Create the top module of the core and connect it with the ports in "outer" -//} + + // If your core is in Verilog (assume your blackbox is called "MyCoreBlackbox"), instantiate it here like + // val core = Module(new MyCoreBlackbox(params...)) + // (as described in the blackbox tutorial) and connect appropriate signals. See the blackbox tutorial + // (link on the top of the page) for more info. + // You can look at https://github.com/ucb-bar/ariane-wrapper/blob/master/src/main/scala/ArianeTile.scala + // for a Verilog example. + + // If your core is in Chisel, you can simply instantiate the top module here like other Chisel module + // and connect appropriate signal. You can even implement this class as your top module. + // See https://github.com/riscv-boom/riscv-boom/blob/master/src/main/scala/common/tile.scala and + // https://github.com/chipsalliance/rocket-chip/blob/master/src/main/scala/tile/RocketTile.scala for + // Chisel example. + // DOC include end: Implementation class // DOC include start: connect interrupt From 2c7e7f3199d497668a20d8a635dfb2aeca27b81d Mon Sep 17 00:00:00 2001 From: Zitao Fang Date: Sun, 19 Jul 2020 21:36:50 -0700 Subject: [PATCH 40/42] Fixed file links --- docs/Customization/Custom-Core.rst | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/docs/Customization/Custom-Core.rst b/docs/Customization/Custom-Core.rst index 3d6a6393..fa14fff6 100644 --- a/docs/Customization/Custom-Core.rst +++ b/docs/Customization/Custom-Core.rst @@ -35,11 +35,14 @@ where ``TileType`` is the tile class (see the next section). All custom cores will also need to implement ``instantiate()`` in their tile parameter class to return a new instance of the tile class ``TileType``. -``TileParams``, ``InstantiableTileParams[TileType]`` and ``CoreParams`` contains the following fields: +``TileParams`` (in the file `BaseTile.scala `_) , +``InstantiableTileParams`` (in the file `BaseTile.scala `_), +``CoreParams`` (in the file `Core.scala `_), +and ``FPUParams`` (in the file `FPU.scala `_) +contains the following fields: .. code-block:: scala - // The two classes below can be found in https://github.com/chipsalliance/rocket-chip/blob/master/src/main/scala/tile/BaseTile.scala. trait TileParams { val core: CoreParams // Core parameters (see below) val icache: Option[ICacheParams] // Rocket specific: I1 cache option @@ -56,7 +59,6 @@ of the tile class ``TileType``. (implicit p: Parameters): TileType } - // This class can be found in https://github.com/chipsalliance/rocket-chip/blob/master/src/main/scala/tile/Core.scala. trait CoreParams { val bootFreqHz: BigInt // Frequency val useVM: Boolean // Support virtual memory @@ -106,8 +108,7 @@ of the tile class ``TileType``. def eLen(xLen: Int, fLen: Int): Int = xLen max fLen def vMemDataBits: Int = 0 } - - // This class can be found in https://github.com/chipsalliance/rocket-chip/blob/master/src/main/scala/tile/FPU.scala. + case class FPUParams( minFLen: Int = 32, // Minimum floating point length (no need to change) fLen: Int = 64, // Maximum floating point length, use 32 if only single precision is supported @@ -191,11 +192,11 @@ Make sure to read :ref:`node_types` to check out what type of nodes Chipyard sup Also, by default, there are boundary buffers for both master and slave connections to the bus when they are leaving the tile, and you can override the following two functions to control how to buffer the bus requests/responses: +(You can find the definition of these two functions in the class ``BaseTile`` in the file +`BaseTile.scala `_) .. code-block:: scala - // This two functions can be found in https://github.com/chipsalliance/rocket-chip/blob/master/src/main/scala/tile/BaseTile.scala, - // in the class "BaseTile". // By default, their value is "TLBuffer(BufferParams.none)". protected def makeMasterBoundaryBuffers(implicit p: Parameters): TLBuffer protected def makeSlaveBoundaryBuffers(implicit p: Parameters): TLBuffer @@ -232,11 +233,11 @@ Chipyard allows a tile to either receive interrupts from other devices or initia In the tile that inherited ``SinksExternalInterrupts``, one can create a ``TileInterrupts`` object (a Chisel bundle) and call ``decodeCoreInterrupts()`` with the object as the argument. Note that you should call this function in the implementation class since it returns a Chisel bundle used by RTL code. You can then read the interrupt bits from the ``TileInterrupts`` bundle -we create above. The definition of ``TileInterrupts`` is +we create above. The definition of ``TileInterrupts`` +(in the file `Interrupts.scala `_) is .. code-block:: scala - // This class can be found in https://github.com/chipsalliance/rocket-chip/blob/master/src/main/scala/tile/Interrupts.scala. class TileInterrupts(implicit p: Parameters) extends CoreBundle()(p) { val debug = Bool() // debug interrupt val mtip = Bool() // Machine level timer interrupt @@ -255,11 +256,11 @@ Here is an example on how to connect these signals in the implementation class: Also, the tile can also notify other cores or devices for some events by calling following functions in ``SourcesExternalNotifications`` from the implementation class: +(These functions can be found in in the trait ``SourcesExternalNotifications`` in the file +`Interrupts.scala `_) .. code-block:: scala - // These functions can be found in https://github.com/chipsalliance/rocket-chip/blob/master/src/main/scala/tile/Interrupts.scala, - // in the trait "SourcesExternalNotifications". def reportHalt(could_halt: Option[Bool]) // Triggered when there is an unrecoverable hardware error (halt the machine) def reportHalt(errors: Seq[CanHaveErrors]) // Varient for standard error bundle (Rocket specific: used only by cache when there's an ECC error) def reportCease(could_cease: Option[Bool], quiescenceCycles: Int = 8) // Triggered when the core stop retiring instructions (like clock gating) From 0a39819f442ce54d3b280870eab0d3e398235f6c Mon Sep 17 00:00:00 2001 From: Zitao Fang Date: Sun, 19 Jul 2020 21:46:32 -0700 Subject: [PATCH 41/42] Add source file note --- docs/Customization/Custom-Core.rst | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/docs/Customization/Custom-Core.rst b/docs/Customization/Custom-Core.rst index fa14fff6..4f529efc 100644 --- a/docs/Customization/Custom-Core.rst +++ b/docs/Customization/Custom-Core.rst @@ -10,6 +10,11 @@ instructions on how to achieve this. RoCC is currently not supported by cores other than Rocket and BOOM. Please use Rocket or BOOM as the RoCC base core if you need to use RoCC. +.. note:: + + This page contains links to the files that contains important definitions in the Rocket chip repository, which is maintained separately + from Chipyard. If you find any discrepency between the code on this page and the code in the source file, please report it through + GitHub issues! Wrap Verilog Module with Blackbox (Optional) -------------------------------------------- From 692b120b65ab72f6e3f1a7885efed74057b08747 Mon Sep 17 00:00:00 2001 From: Zitao Fang Date: Sun, 19 Jul 2020 21:48:07 -0700 Subject: [PATCH 42/42] Fixed typo --- docs/Customization/Custom-Core.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/Customization/Custom-Core.rst b/docs/Customization/Custom-Core.rst index 4f529efc..a76741ec 100644 --- a/docs/Customization/Custom-Core.rst +++ b/docs/Customization/Custom-Core.rst @@ -13,7 +13,7 @@ instructions on how to achieve this. .. note:: This page contains links to the files that contains important definitions in the Rocket chip repository, which is maintained separately - from Chipyard. If you find any discrepency between the code on this page and the code in the source file, please report it through + from Chipyard. If you find any discrepancy between the code on this page and the code in the source file, please report it through GitHub issues! Wrap Verilog Module with Blackbox (Optional)