Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Standardize Tile Instantiation and Attachment #2504

Merged
merged 15 commits into from
Jun 18, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ object LogicalModuleTree {

def rootLogicalTreeNode: LogicalTreeNode = {
val roots = tree.collect { case (k, _) if !tree.exists(_._2.contains(k)) => k }
assert(roots.size == 1, "Logical Tree contains more than one root.")
require(roots.size == 1, s"Logical Tree contains more than one root:\n$roots")
roots.head
}

Expand Down
73 changes: 52 additions & 21 deletions src/main/scala/groundtest/Configs.scala
Original file line number Diff line number Diff line change
Expand Up @@ -5,36 +5,67 @@ package freechips.rocketchip.groundtest

import Chisel._
import freechips.rocketchip.config.Config
import freechips.rocketchip.devices.tilelink.{CLINTKey, PLICKey}
import freechips.rocketchip.devices.debug.{DebugModuleKey}
import freechips.rocketchip.subsystem._
import freechips.rocketchip.system.BaseConfig
import freechips.rocketchip.rocket.{DCacheParams}
import freechips.rocketchip.tile.{MaxHartIdBits, XLen}
import freechips.rocketchip.tile.{XLen}

/** Actual testing target Configs */

class TraceGenConfig extends Config(new WithTraceGen(List.fill(2){ DCacheParams(nSets = 16, nWays = 1) }) ++ new BaseConfig)
class TraceGenConfig extends Config(
new WithTraceGen(2)() ++
new GroundTestBaseConfig
)

class TraceGenBufferlessConfig extends Config(new WithBufferlessBroadcastHub ++ new TraceGenConfig)
class TraceGenBufferlessConfig extends Config(
new WithBufferlessBroadcastHub ++
new TraceGenConfig
)

/* Composable Configs to set individual parameters */

class WithTraceGen(params: Seq[DCacheParams], nReqs: Int = 8192) extends Config((site, here, up) => {
case GroundTestTilesKey => params.map { dcp => TraceGenParams(
dcache = Some(dcp),
wordBits = site(XLen),
addrBits = 32,
addrBag = {
val nSets = dcp.nSets
val nWays = dcp.nWays
val blockOffset = site(SystemBusKey).blockOffset
val nBeats = site(SystemBusKey).blockBeats
List.tabulate(nWays) { i =>
Seq.tabulate(nBeats) { j => BigInt((j * 8) + ((i * nSets) << blockOffset)) }
}.flatten
},
maxRequests = nReqs,
memStart = site(ExtMem).get.master.base,
numGens = params.size)
class GroundTestBaseConfig extends Config(
new BaseConfig().alter((site,here,up) => {
case DebugModuleKey => None
case CLINTKey => None
case PLICKey => None
})
)

class WithTraceGen(
n: Int = 2,
overrideIdOffset: Option[Int] = None,
overrideMemOffset: Option[BigInt] = None)(
params: Seq[DCacheParams] = List.fill(n){ DCacheParams(nSets = 16, nWays = 1) },
nReqs: Int = 8192
) extends Config((site, here, up) => {
case TilesLocated(InSubsystem) => {
val prev = up(TilesLocated(InSubsystem), site)
val idOffset = overrideIdOffset.getOrElse(prev.size)
val memOffset: BigInt = overrideMemOffset.orElse(site(ExtMem).map(_.master.base)).getOrElse(0x0L)
params.zipWithIndex.map { case (dcp, i) =>
TraceGenTileAttachParams(
tileParams = TraceGenParams(
hartId = i + idOffset,
dcache = Some(dcp),
wordBits = site(XLen),
addrBits = 32,
addrBag = {
val nSets = dcp.nSets
val nWays = dcp.nWays
val blockOffset = site(SystemBusKey).blockOffset
val nBeats = site(SystemBusKey).blockBeats
List.tabulate(nWays) { i =>
Seq.tabulate(nBeats) { j => BigInt((j * 8) + ((i * nSets) << blockOffset)) }
}.flatten
},
maxRequests = nReqs,
memStart = memOffset,
numGens = params.size),
crossingParams = RocketCrossingParams()
)
} ++ prev
}
case MaxHartIdBits => log2Up(params.size)
})
40 changes: 17 additions & 23 deletions src/main/scala/groundtest/GroundTestSubsystem.scala
Original file line number Diff line number Diff line change
Expand Up @@ -3,30 +3,24 @@
package freechips.rocketchip.groundtest

import Chisel._
import freechips.rocketchip.config.{Field, Parameters}
import freechips.rocketchip.diplomacy._
import freechips.rocketchip.diplomaticobjectmodel.model.OMInterrupt
import freechips.rocketchip.interrupts._
import freechips.rocketchip.subsystem._
import freechips.rocketchip.tilelink._
import freechips.rocketchip.tile._

import scala.math.max

case object TileId extends Field[Int]

class GroundTestSubsystem(implicit p: Parameters) extends BaseSubsystem
with CanHaveMasterAXI4MemPort {
val tileParams = p(GroundTestTilesKey)
val tiles = tileParams.zipWithIndex.map { case(c, i) => LazyModule(c.build(i, p)) }

tiles.map(_.masterNode).foreach { m =>
sbus.fromTile(None, buffer = BufferParams.default){ m }
}

import chisel3.dontTouch
import freechips.rocketchip.config.{Parameters}
import freechips.rocketchip.diplomacy.{AddressSet, LazyModule}
import freechips.rocketchip.interrupts.{IntSinkNode, IntSinkPortSimple}
import freechips.rocketchip.subsystem.{BaseSubsystem, BaseSubsystemModuleImp, HasTiles, CanHaveMasterAXI4MemPort}
import freechips.rocketchip.tilelink.{TLRAM, TLFragmenter}

class GroundTestSubsystem(implicit p: Parameters)
extends BaseSubsystem
with HasTiles
with CanHaveMasterAXI4MemPort
{
val testram = LazyModule(new TLRAM(AddressSet(0x52000000, 0xfff), beatBytes=pbus.beatBytes))
pbus.coupleTo("TestRAM") { testram.node := TLFragmenter(pbus) := _ }

// No cores to monitor
def coreMonitorBundles = Nil

// No PLIC in ground test; so just sink the interrupts to nowhere
IntSinkNode(IntSinkPortSimple()) :=* ibus.toPLIC

Expand All @@ -38,6 +32,6 @@ class GroundTestSubsystemModuleImp[+L <: GroundTestSubsystem](_outer: L) extends

outer.tiles.zipWithIndex.map { case(t, i) => t.module.constants.hartid := UInt(i) }

val status = DebugCombiner(outer.tiles.map(_.module.status))
success := status.finished
val status = dontTouch(DebugCombiner(outer.tiles.collect { case t: GroundTestTile => t.module.status }))
success := outer.tileCeaseSinkNode.in.head._1.asUInt.andR
}
3 changes: 0 additions & 3 deletions src/main/scala/groundtest/Status.scala
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,15 @@ import Chisel._
import freechips.rocketchip.util.ValidMux

class GroundTestStatus extends Bundle {
val finished = Bool(OUTPUT)
val timeout = Valid(UInt(width = 4))
val error = Valid(UInt(width = 4))
}

object DebugCombiner {
def apply(debugs: Seq[GroundTestStatus]): GroundTestStatus = {
val out = Wire(new GroundTestStatus)
out.finished := debugs.map(_.finished).reduce(_ && _)
out.timeout := ValidMux(debugs.map(_.timeout))
out.error := ValidMux(debugs.map(_.error))
out
}
}

20 changes: 9 additions & 11 deletions src/main/scala/groundtest/Tile.scala
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,6 @@ trait GroundTestTileParams extends TileParams {
val memStart: BigInt
val maxRequests: Int
val numGens: Int

def build(i: Int, p: Parameters): GroundTestTile

val icache = Some(ICacheParams())
val btb = None
Expand All @@ -28,18 +26,18 @@ trait GroundTestTileParams extends TileParams {
val dataScratchpadBytes = 0
}

case object GroundTestTilesKey extends Field[Seq[GroundTestTileParams]]

abstract class GroundTestTile private (params: GroundTestTileParams, x: ClockCrossingType, q: Parameters)
extends BaseTile(params, x, HartsWontDeduplicate(params), q)
abstract class GroundTestTile(
params: GroundTestTileParams,
crossing: ClockCrossingType,
lookup: LookupByHartIdImpl,
q: Parameters
) extends BaseTile(params, crossing, lookup, q)
with SinksExternalInterrupts
with SourcesExternalNotifications
{
def this(params: GroundTestTileParams)(implicit p: Parameters) = this(params, SynchronousCrossing(), p)
val intInwardNode: IntInwardNode = IntIdentityNode()
val cpuDevice: SimpleDevice = new SimpleDevice("groundtest", Nil)
val intOutwardNode: IntOutwardNode = IntIdentityNode()
val slaveNode: TLInwardNode = TLIdentityNode()
val ceaseNode: IntOutwardNode = IntIdentityNode()
val haltNode: IntOutwardNode = IntIdentityNode()
val wfiNode: IntOutwardNode = IntIdentityNode()

val dcacheOpt = params.dcache.map { dc => LazyModule(
if (dc.nMSHRs == 0) new DCache(hartId, crossing)
Expand Down
46 changes: 36 additions & 10 deletions src/main/scala/groundtest/TraceGen.scala
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,12 @@
package freechips.rocketchip.groundtest

import Chisel._
import freechips.rocketchip.config.{Field, Parameters}
import freechips.rocketchip.config.{Parameters}
import freechips.rocketchip.diplomacy.{ClockCrossingType}
import freechips.rocketchip.rocket._
import freechips.rocketchip.tile._
import freechips.rocketchip.tilelink._
import freechips.rocketchip.subsystem.{TileCrossingParamsLike, CanAttachTile}
import freechips.rocketchip.util._

// =======
Expand Down Expand Up @@ -57,15 +59,19 @@ import freechips.rocketchip.util._
// to repeatedly recompile with a different address bag.)

case class TraceGenParams(
dcache: Option[DCacheParams] = Some(DCacheParams()),
wordBits: Int, // p(XLen)
addrBits: Int, // p(PAddrBits)
addrBag: List[BigInt], // p(AddressBag)
maxRequests: Int,
memStart: BigInt, //p(ExtMem).base
numGens: Int) extends GroundTestTileParams {
def build(i: Int, p: Parameters): GroundTestTile = new TraceGenTile(i, this)(p)
val hartId = 0
numGens: Int,
dcache: Option[DCacheParams] = Some(DCacheParams()),
hartId: Int = 0
) extends InstantiableTileParams[TraceGenTile] with GroundTestTileParams
{
def instantiate(crossing: TileCrossingParamsLike, lookup: LookupByHartIdImpl)(implicit p: Parameters): TraceGenTile = {
new TraceGenTile(this, crossing, lookup)
}
val beuAddr = None
val blockerCtrlAddr = None
val name = None
Expand Down Expand Up @@ -94,6 +100,15 @@ trait HasTraceGenParams {
require((1 << logAddressBagLen) == addressBagLen)
}

case class TraceGenTileAttachParams(
tileParams: TraceGenParams,
crossingParams: TileCrossingParamsLike
) extends CanAttachTile {
type TileType = TraceGenTile
val lookup: LookupByHartIdImpl = HartsWontDeduplicate(tileParams)
}


// ============
// Trace format
// ============
Expand Down Expand Up @@ -578,9 +593,18 @@ class TraceGenerator(val params: TraceGenParams)(implicit val p: Parameters) ext
// Trace-generator wrapper
// =======================

class TraceGenTile(hack: Int, val id: Int, val params: TraceGenParams, q: Parameters) extends GroundTestTile(params)(q) {
def this(id: Int, params: TraceGenParams)(implicit p: Parameters) = this(0, id, params, p)
val masterNode: TLOutwardNode = TLIdentityNode() := visibilityNode := dcacheOpt.map(_.node).getOrElse(TLIdentityNode())
class TraceGenTile private(
val params: TraceGenParams,
crossing: ClockCrossingType,
lookup: LookupByHartIdImpl,
q: Parameters
) extends GroundTestTile(params, crossing, lookup, q)
{
def this(params: TraceGenParams, crossing: TileCrossingParamsLike, lookup: LookupByHartIdImpl)(implicit p: Parameters) =
this(params, crossing.crossingType, lookup, p)

val masterNode: TLOutwardNode = TLIdentityNode() := visibilityNode := dcacheOpt.map(_.node).getOrElse(TLTempNode())

override lazy val module = new TraceGenTileModuleImp(this)
}

Expand All @@ -595,10 +619,12 @@ class TraceGenTileModuleImp(outer: TraceGenTile) extends GroundTestTileModuleImp
dcache.module.io.cpu <> dcacheIF.io.cache
}

status.finished := tracegen.io.finished
outer.reportCease(Some(tracegen.io.finished))
outer.reportHalt(Some(tracegen.io.timeout))
outer.reportWFI(None)
status.timeout.valid := tracegen.io.timeout
status.timeout.bits := UInt(0)
status.error.valid := Bool(false)

assert(!tracegen.io.timeout, s"TraceGen tile ${outer.id}: request timed out")
assert(!tracegen.io.timeout, s"TraceGen tile ${outer.tileParams.hartId}: request timed out")
}
36 changes: 29 additions & 7 deletions src/main/scala/subsystem/Configs.scala
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ class BaseSubsystemConfig extends Config ((site, here, up) => {
// Tile parameters
case PgLevels => if (site(XLen) == 64) 3 /* Sv39 */ else 2 /* Sv32 */
case XLen => 64 // Applies to all cores
case MaxHartIdBits => log2Up(site(RocketTilesKey).size)
case MaxHartIdBits => log2Up(site(TilesLocated(InSubsystem)).map(_.tileParams.hartId).max+1)
// Interconnect parameters
case SystemBusKey => SystemBusParams(
beatBytes = site(XLen)/8,
Expand All @@ -41,6 +41,8 @@ class BaseSubsystemConfig extends Config ((site, here, up) => {
case DebugModuleKey => Some(DefaultDebugModuleParams(site(XLen)))
case CLINTKey => Some(CLINTParams())
case PLICKey => Some(PLICParams())
case TilesLocated(InSubsystem) =>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will there be an example for what direct manipulation of the TilesLocated pattern looks like? (Not using the LegacyTileFieldHelper)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good suggestion, will do

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I ended up doing this example in WithTraceGen for the TraceGenTile subtype. I'm not very keen to mess too much with the existing RocketTilesKey Config alterations since it it seems hard to change them while remaining backwards compatibly with external alterations of RocketTilesKey. Check out WithTraceGen and HeterogeneousTileExampleConfig and let me know if that is sufficiently helpful.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, this is pretty clear.

I noticed that manipulation of core parameters is more verbose without direct access through CoreTilesKey, since the type of the core must be matched, and since AttachParams adds another layer of case-class nesting. Given that manipulating tile-level parameters is the common use-case of the core-specific TilesKey s, it may be worth defining a generic macro to modify the TileParams matching some desired Tile type.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if you can figure out a good pattern for applying a "lens" to nested case classes in Config alterations I will buy you a beer

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But yes something specific to this particular use case is probably also possible

LegacyTileFieldHelper(site(RocketTilesKey), site(RocketCrossingKey), RocketTileAttachParams.apply _)
})

/* Composable partial function Configs to set individual parameters */
Expand Down Expand Up @@ -75,8 +77,10 @@ class WithCoherentBusTopology extends Config((site, here, up) => {
l2 = site(BankedL2Key)))
})

class WithNBigCores(n: Int) extends Config((site, here, up) => {
class WithNBigCores(n: Int, overrideIdOffset: Option[Int] = None) extends Config((site, here, up) => {
case RocketTilesKey => {
val prev = up(RocketTilesKey, site)
val idOffset = overrideIdOffset.getOrElse(prev.size)
val big = RocketTileParams(
core = RocketCoreParams(mulDiv = Some(MulDivParams(
mulUnroll = 8,
Expand All @@ -89,12 +93,14 @@ class WithNBigCores(n: Int) extends Config((site, here, up) => {
icache = Some(ICacheParams(
rowBits = site(SystemBusKey).beatBits,
blockBytes = site(CacheBlockBytes))))
List.tabulate(n)(i => big.copy(hartId = i))
List.tabulate(n)(i => big.copy(hartId = i + idOffset)) ++ prev
}
})

class WithNMedCores(n: Int) extends Config((site, here, up) => {
class WithNMedCores(n: Int, overrideIdOffset: Option[Int] = None) extends Config((site, here, up) => {
case RocketTilesKey => {
val prev = up(RocketTilesKey, site)
val idOffset = overrideIdOffset.getOrElse(prev.size)
val med = RocketTileParams(
core = RocketCoreParams(fpu = None),
btb = None,
Expand All @@ -111,12 +117,14 @@ class WithNMedCores(n: Int) extends Config((site, here, up) => {
nWays = 1,
nTLBEntries = 4,
blockBytes = site(CacheBlockBytes))))
List.tabulate(n)(i => med.copy(hartId = i))
List.tabulate(n)(i => med.copy(hartId = i + idOffset)) ++ prev
}
})

class WithNSmallCores(n: Int) extends Config((site, here, up) => {
class WithNSmallCores(n: Int, overrideIdOffset: Option[Int] = None) extends Config((site, here, up) => {
case RocketTilesKey => {
val prev = up(RocketTilesKey, site)
val idOffset = overrideIdOffset.getOrElse(prev.size)
val small = RocketTileParams(
core = RocketCoreParams(useVM = false, fpu = None),
btb = None,
Expand All @@ -133,7 +141,7 @@ class WithNSmallCores(n: Int) extends Config((site, here, up) => {
nWays = 1,
nTLBEntries = 4,
blockBytes = site(CacheBlockBytes))))
List.tabulate(n)(i => small.copy(hartId = i))
List.tabulate(n)(i => small.copy(hartId = i + idOffset)) ++ prev
}
})

Expand Down Expand Up @@ -410,3 +418,17 @@ class WithScratchpadsOnly extends Config((site, here, up) => {
scratch = Some(0x80000000L))))
}
})

/** Boilerplate code for translating between the old XTilesParamsKey/XTilesCrossingKey pattern and new TilesLocated pattern */
object LegacyTileFieldHelper {
def apply[TPT <: InstantiableTileParams[_], TCT <: TileCrossingParamsLike, TAP <: CanAttachTile](
tileParams: Seq[TPT],
tcp: Seq[TCT],
apply: (TPT, TCT, LookupByHartIdImpl) => TAP): Seq[TAP] =
{
val crossingParams = heterogeneousOrGlobalSetting(tcp, tileParams.size)
tileParams.zip(crossingParams).map { case (t, c) =>
apply(t, c, PriorityMuxHartIdFromSeq(tileParams))
}
}
}
Loading