diff --git a/src/main/scala/devices/debug/Custom.scala b/src/main/scala/devices/debug/Custom.scala index 22086988a28..64e3f944ca0 100644 --- a/src/main/scala/devices/debug/Custom.scala +++ b/src/main/scala/devices/debug/Custom.scala @@ -5,8 +5,7 @@ package freechips.rocketchip.devices.debug import chisel3._ import chisel3.util._ import chisel3.experimental.SourceInfo -import freechips.rocketchip.diplomacy.{LazyModule, LazyModuleImp, NexusNode, RenderedEdge, - SimpleNodeImp, SinkNode, SourceNode, ValName} +import freechips.rocketchip.diplomacy._ import org.chipsalliance.cde.config.Parameters case class DebugCustomParams( @@ -68,7 +67,7 @@ class DebugCustomXbar( ) lazy val module = new Impl - class Impl extends LazyModuleImp(this) { + class Impl extends LazyRawModuleImp(this) { // require only one sink require(node.out.size == 1, "Must have exactly one sink node, not ${node.out.size}") // send address to all sources diff --git a/src/main/scala/devices/debug/Debug.scala b/src/main/scala/devices/debug/Debug.scala index fec2caa14a3..d8f8371fd79 100755 --- a/src/main/scala/devices/debug/Debug.scala +++ b/src/main/scala/devices/debug/Debug.scala @@ -693,7 +693,8 @@ class TLDebugModuleOuterAsync(device: Device)(implicit p: Parameters) extends La }) val dmOuter = LazyModule( new TLDebugModuleOuter(device)) - val intnode = IntSyncCrossingSource(alreadyRegistered = true) :*= dmOuter.intnode + val intnode = IntSyncIdentityNode() + intnode :*= IntSyncCrossingSource(alreadyRegistered = true) :*= dmOuter.intnode val dmiBypass = LazyModule(new TLBusBypass(beatBytes=4, bufferError=false, maxAtomic=0, maxTransfer=4)) val dmiInnerNode = TLAsyncCrossingSource() := dmiBypass.node := dmiXbar.node @@ -727,6 +728,7 @@ class TLDebugModuleOuterAsync(device: Device)(implicit p: Parameters) extends La childClock := io.dmi_clock childReset := io.dmi_reset + override def provideImplicitClockToLazyChildren = true withClockAndReset(childClock, childReset) { dmi2tlOpt.foreach { _.module.io.dmi <> io.dmi.get } @@ -1898,6 +1900,7 @@ class TLDebugModuleInnerAsync(device: Device, getNComponents: () => Int, beatByt childClock := io.debug_clock childReset := io.debug_reset + override def provideImplicitClockToLazyChildren = true val dmactive_synced = withClockAndReset(childClock, childReset) { val dmactive_synced = AsyncResetSynchronizerShiftReg(in=io.dmactive, sync=3, name=Some("dmactiveSync")) @@ -1986,6 +1989,7 @@ class TLDebugModule(beatBytes: Int)(implicit p: Parameters) extends LazyModule { childClock := io.tl_clock childReset := io.tl_reset + override def provideImplicitClockToLazyChildren = true dmOuter.module.io.dmi.foreach { dmOuterDMI => dmOuterDMI <> io.dmi.get.dmi diff --git a/src/main/scala/devices/debug/Periphery.scala b/src/main/scala/devices/debug/Periphery.scala index 009372078c6..fcf5826dc0b 100644 --- a/src/main/scala/devices/debug/Periphery.scala +++ b/src/main/scala/devices/debug/Periphery.scala @@ -99,7 +99,7 @@ trait HasPeripheryDebug { this: BaseSubsystem => tlDM } - lazy val debugNode = debugOpt.map(_.intnode).getOrElse(IntSyncXbar() := NullIntSyncSource()) + val debugNode = debugOpt.map(_.intnode) val psd = InModuleBody { val psd = IO(new PSDIO) diff --git a/src/main/scala/devices/tilelink/BootROM.scala b/src/main/scala/devices/tilelink/BootROM.scala index 9ffdac9e65e..2bbcb16be97 100644 --- a/src/main/scala/devices/tilelink/BootROM.scala +++ b/src/main/scala/devices/tilelink/BootROM.scala @@ -5,10 +5,9 @@ package freechips.rocketchip.devices.tilelink import chisel3._ import chisel3.util.log2Ceil import org.chipsalliance.cde.config.{Field, Parameters} -import freechips.rocketchip.subsystem.{BaseSubsystem, HierarchicalLocation, HasTiles, TLBusWrapperLocation} +import freechips.rocketchip.subsystem._ import freechips.rocketchip.diplomacy._ import freechips.rocketchip.tilelink._ -import freechips.rocketchip.prci.{ClockSinkDomain} import java.nio.ByteBuffer import java.nio.file.{Files, Paths} @@ -66,11 +65,10 @@ object BootROM { * at a configurable location, but also drives the tiles' reset vectors to point * at its 'hang' address parameter value. */ - def attach(params: BootROMParams, subsystem: BaseSubsystem with HasTiles, where: TLBusWrapperLocation) + def attach(params: BootROMParams, subsystem: BaseSubsystem with HasHierarchicalElements with HasTileInputConstants, where: TLBusWrapperLocation) (implicit p: Parameters): TLROM = { val tlbus = subsystem.locateTLBusWrapper(where) - val bootROMDomainWrapper = LazyModule(new ClockSinkDomain(take = None)) - bootROMDomainWrapper.clockNode := tlbus.fixedClockNode + val bootROMDomainWrapper = tlbus.generateSynchronousDomain.suggestName("bootrom_domain") val bootROMResetVectorSourceNode = BundleBridgeSource[UInt]() lazy val contents = { diff --git a/src/main/scala/devices/tilelink/CLINT.scala b/src/main/scala/devices/tilelink/CLINT.scala index 8156706ee8d..d83bde22899 100644 --- a/src/main/scala/devices/tilelink/CLINT.scala +++ b/src/main/scala/devices/tilelink/CLINT.scala @@ -102,18 +102,17 @@ class CLINT(params: CLINTParams, beatBytes: Int)(implicit p: Parameters) extends /** Trait that will connect a CLINT to a subsystem */ trait CanHavePeripheryCLINT { this: BaseSubsystem => - val clintOpt = p(CLINTKey).map { params => + val (clintOpt, clintDomainOpt, clintTickOpt) = p(CLINTKey).map { params => val tlbus = locateTLBusWrapper(p(CLINTAttachKey).slaveWhere) - val clint = LazyModule(new CLINT(params, cbus.beatBytes)) - clint.node := tlbus.coupleTo("clint") { TLFragmenter(tlbus) := _ } - - // Override the implicit clock and reset -- could instead include a clockNode in the clint, and make it a RawModuleImp? - InModuleBody { - clint.module.clock := tlbus.module.clock - clint.module.reset := tlbus.module.reset - } - - clint - - } + val clintDomainWrapper = tlbus.generateSynchronousDomain.suggestName("clint_domain") + val clint = clintDomainWrapper { LazyModule(new CLINT(params, cbus.beatBytes)) } + clintDomainWrapper { clint.node := tlbus.coupleTo("clint") { TLFragmenter(tlbus) := _ } } + val clintTick = clintDomainWrapper { InModuleBody { + val tick = IO(Input(Bool())) + clint.module.io.rtcTick := tick + tick + }} + + (clint, clintDomainWrapper, clintTick) + }.unzip3 } diff --git a/src/main/scala/devices/tilelink/Plic.scala b/src/main/scala/devices/tilelink/Plic.scala index 3e6de570423..8d87e74f37b 100644 --- a/src/main/scala/devices/tilelink/Plic.scala +++ b/src/main/scala/devices/tilelink/Plic.scala @@ -12,7 +12,6 @@ import freechips.rocketchip.tilelink._ import freechips.rocketchip.interrupts._ import freechips.rocketchip.util._ import freechips.rocketchip.util.property -import freechips.rocketchip.prci.{ClockSinkDomain} import chisel3.experimental.SourceInfo import scala.math.min @@ -355,15 +354,14 @@ class PLICFanIn(nDevices: Int, prioBits: Int) extends Module { /** Trait that will connect a PLIC to a subsystem */ trait CanHavePeripheryPLIC { this: BaseSubsystem => - val plicOpt = p(PLICKey).map { params => + val (plicOpt, plicDomainOpt) = p(PLICKey).map { params => val tlbus = locateTLBusWrapper(p(PLICAttachKey).slaveWhere) - val plicDomainWrapper = LazyModule(new ClockSinkDomain(take = None)) - plicDomainWrapper.clockNode := tlbus.fixedClockNode + val plicDomainWrapper = tlbus.generateSynchronousDomain val plic = plicDomainWrapper { LazyModule(new TLPLIC(params, tlbus.beatBytes)) } - plic.node := tlbus.coupleTo("plic") { TLFragmenter(tlbus) := _ } - plic.intnode :=* ibus.toPLIC + plicDomainWrapper { plic.node := tlbus.coupleTo("plic") { TLFragmenter(tlbus) := _ } } + plicDomainWrapper { plic.intnode :=* ibus.toPLIC } - plic - } + (plic, plicDomainWrapper) + }.unzip } diff --git a/src/main/scala/diplomacy/BundleBridge.scala b/src/main/scala/diplomacy/BundleBridge.scala index e02d6f4f966..f8a70371a6c 100644 --- a/src/main/scala/diplomacy/BundleBridge.scala +++ b/src/main/scala/diplomacy/BundleBridge.scala @@ -124,7 +124,7 @@ class BundleBridgeNexus[T <: Data]( val node = BundleBridgeNexusNode[T](default, inputRequiresOutput) lazy val module = new Impl - class Impl extends LazyModuleImp(this) { + class Impl extends LazyRawModuleImp(this) { val defaultWireOpt = default.map(_()) val inputs: Seq[T] = node.in.map(_._1) inputs.foreach { i => require(DataMirror.checkTypeEquivalence(i, inputs.head), diff --git a/src/main/scala/diplomacy/LazyModule.scala b/src/main/scala/diplomacy/LazyModule.scala index a761a841eed..a6b0791f231 100644 --- a/src/main/scala/diplomacy/LazyModule.scala +++ b/src/main/scala/diplomacy/LazyModule.scala @@ -415,7 +415,11 @@ class LazyRawModuleImp(val wrapper: LazyModule) extends RawModule with LazyModul // the default is that these are disabled childClock := false.B.asClock childReset := chisel3.DontCare - val (auto, dangles) = withClockAndReset(childClock, childReset) { + + def provideImplicitClockToLazyChildren: Boolean = false + val (auto, dangles) = if (provideImplicitClockToLazyChildren) { + withClockAndReset(childClock, childReset) { instantiate() } + } else { instantiate() } } @@ -427,6 +431,10 @@ class LazyRawModuleImp(val wrapper: LazyModule) extends RawModule with LazyModul class SimpleLazyModule(implicit p: Parameters) extends LazyModule { lazy val module = new LazyModuleImp(this) } +class SimpleLazyRawModule(implicit p: Parameters) extends LazyModule { + lazy val module = new LazyRawModuleImp(this) +} + /** Allows dynamic creation of [[Module]] hierarchy and "shoving" logic into a [[LazyModule]]. */ trait LazyScope { diff --git a/src/main/scala/groundtest/Configs.scala b/src/main/scala/groundtest/Configs.scala index bb0ccd71ab5..cf7a283e732 100644 --- a/src/main/scala/groundtest/Configs.scala +++ b/src/main/scala/groundtest/Configs.scala @@ -30,25 +30,24 @@ class GroundTestBaseConfig extends Config( case DebugModuleKey => None case CLINTKey => None case PLICKey => None - case SubsystemExternalResetVectorKey => true + case HasTilesExternalResetVectorKey => true }) ) 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 idOffset = up(NumTiles) val memOffset: BigInt = overrideMemOffset.orElse(site(ExtMem).map(_.master.base)).getOrElse(0x0L) params.zipWithIndex.map { case (dcp, i) => TraceGenTileAttachParams( tileParams = TraceGenParams( - hartId = i + idOffset, + tileId = i + idOffset, dcache = Some(dcp), wordBits = site(XLen), addrBits = 32, @@ -68,4 +67,5 @@ class WithTraceGen( ) } ++ prev } + case NumTiles => up(NumTiles) + n }) diff --git a/src/main/scala/groundtest/GroundTestSubsystem.scala b/src/main/scala/groundtest/GroundTestSubsystem.scala index ba3215f7f53..379ed58aaca 100644 --- a/src/main/scala/groundtest/GroundTestSubsystem.scala +++ b/src/main/scala/groundtest/GroundTestSubsystem.scala @@ -4,15 +4,21 @@ package freechips.rocketchip.groundtest import chisel3._ import org.chipsalliance.cde.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.diplomacy._ +import freechips.rocketchip.interrupts._ +import freechips.rocketchip.tile.{NMI} +import freechips.rocketchip.devices.tilelink.{CLINTConsts} +import freechips.rocketchip.subsystem._ import freechips.rocketchip.tilelink.{TLRAM, TLFragmenter} import freechips.rocketchip.interrupts.{NullIntSyncSource} class GroundTestSubsystem(implicit p: Parameters) extends BaseSubsystem - with HasTiles + with InstantiatesHierarchicalElements + with HasHierarchicalElementsRootContext + with HasHierarchicalElements + with HasTileNotificationSinks + with HasTileInputConstants with CanHaveMasterAXI4MemPort { val testram = LazyModule(new TLRAM(AddressSet(0x52000000, 0xfff), beatBytes=pbus.beatBytes)) @@ -24,16 +30,18 @@ class GroundTestSubsystem(implicit p: Parameters) // No PLIC in ground test; so just sink the interrupts to nowhere IntSinkNode(IntSinkPortSimple()) :=* ibus.toPLIC - val tileStatusNodes = tiles.collect { case t: GroundTestTile => t.statusNode.makeSink() } - - // no debug module - val debugNode = NullIntSyncSource() + val tileStatusNodes = totalTiles.values.collect { case t: GroundTestTile => t.statusNode.makeSink() } + val clintOpt = None + val clintDomainOpt = None + val debugOpt = None + val plicOpt = None + val plicDomainOpt = None override lazy val module = new GroundTestSubsystemModuleImp(this) } class GroundTestSubsystemModuleImp[+L <: GroundTestSubsystem](_outer: L) extends BaseSubsystemModuleImp(_outer) { val success = IO(Output(Bool())) - val status = dontTouch(DebugCombiner(outer.tileStatusNodes.map(_.bundle))) + val status = dontTouch(DebugCombiner(outer.tileStatusNodes.map(_.bundle).toSeq)) success := outer.tileCeaseSinkNode.in.head._1.asUInt.andR } diff --git a/src/main/scala/groundtest/Tile.scala b/src/main/scala/groundtest/Tile.scala index 912016f8ea4..f7bef2d439f 100644 --- a/src/main/scala/groundtest/Tile.scala +++ b/src/main/scala/groundtest/Tile.scala @@ -34,7 +34,7 @@ abstract class GroundTestTile( with SourcesExternalNotifications { val cpuDevice: SimpleDevice = new SimpleDevice("groundtest", Nil) - val intOutwardNode: IntOutwardNode = IntIdentityNode() + val intOutwardNode = None val slaveNode: TLInwardNode = TLIdentityNode() val statusNode = BundleBridgeSource(() => new GroundTestStatus) diff --git a/src/main/scala/groundtest/TraceGen.scala b/src/main/scala/groundtest/TraceGen.scala index 5c5cba9b5f7..f60c41517cd 100644 --- a/src/main/scala/groundtest/TraceGen.scala +++ b/src/main/scala/groundtest/TraceGen.scala @@ -26,7 +26,7 @@ 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.subsystem.{HierarchicalElementCrossingParamsLike, CanAttachTile} import freechips.rocketchip.util._ import freechips.rocketchip.prci.{ClockSinkParameters} @@ -68,15 +68,15 @@ case class TraceGenParams( memStart: BigInt, //p(ExtMem).base numGens: Int, dcache: Option[DCacheParams] = Some(DCacheParams()), - hartId: Int = 0 + tileId: Int = 0 ) extends InstantiableTileParams[TraceGenTile] with GroundTestTileParams { - def instantiate(crossing: TileCrossingParamsLike, lookup: LookupByHartIdImpl)(implicit p: Parameters): TraceGenTile = { + def instantiate(crossing: HierarchicalElementCrossingParamsLike, lookup: LookupByHartIdImpl)(implicit p: Parameters): TraceGenTile = { new TraceGenTile(this, crossing, lookup) } - val beuAddr = None val blockerCtrlAddr = None - val name = None + val baseName = "tracegentile" + val uniqueName = s"${baseName}_$tileId" val clockSinkParams = ClockSinkParameters() } @@ -105,7 +105,7 @@ trait HasTraceGenParams { case class TraceGenTileAttachParams( tileParams: TraceGenParams, - crossingParams: TileCrossingParamsLike + crossingParams: HierarchicalElementCrossingParamsLike ) extends CanAttachTile { type TileType = TraceGenTile val lookup: LookupByHartIdImpl = HartsWontDeduplicate(tileParams) @@ -617,7 +617,7 @@ class TraceGenTile private( q: Parameters ) extends GroundTestTile(params, crossing, lookup, q) { - def this(params: TraceGenParams, crossing: TileCrossingParamsLike, lookup: LookupByHartIdImpl)(implicit p: Parameters) = + def this(params: TraceGenParams, crossing: HierarchicalElementCrossingParamsLike, lookup: LookupByHartIdImpl)(implicit p: Parameters) = this(params, crossing.crossingType, lookup, p) val masterNode: TLOutwardNode = TLIdentityNode() := visibilityNode := dcacheOpt.map(_.node).getOrElse(TLTempNode()) @@ -644,5 +644,5 @@ class TraceGenTileModuleImp(outer: TraceGenTile) extends GroundTestTileModuleImp status.timeout.bits := 0.U status.error.valid := false.B - assert(!tracegen.io.timeout, s"TraceGen tile ${outer.tileParams.hartId}: request timed out") + assert(!tracegen.io.timeout, s"TraceGen tile ${outer.tileParams.tileId}: request timed out") } diff --git a/src/main/scala/interrupts/Crossing.scala b/src/main/scala/interrupts/Crossing.scala index 77a15480529..b113dfdc538 100644 --- a/src/main/scala/interrupts/Crossing.scala +++ b/src/main/scala/interrupts/Crossing.scala @@ -35,14 +35,16 @@ class IntSyncCrossingSource(alreadyRegistered: Boolean = false)(implicit p: Para { val node = IntSyncSourceNode(alreadyRegistered) - lazy val module = new Impl + lazy val module = if (alreadyRegistered) (new ImplRegistered) else (new Impl) + class Impl extends LazyModuleImp(this) { (node.in zip node.out) foreach { case ((in, edgeIn), (out, edgeOut)) => - if (alreadyRegistered) { - out.sync := in - } else { - out.sync := AsyncResetReg(Cat(in.reverse)).asBools - } + out.sync := AsyncResetReg(Cat(in.reverse)).asBools + } + } + class ImplRegistered extends LazyRawModuleImp(this) { + (node.in zip node.out) foreach { case ((in, edgeIn), (out, edgeOut)) => + out.sync := in } } } @@ -85,7 +87,7 @@ class IntSyncSyncCrossingSink()(implicit p: Parameters) extends LazyModule val node = IntSyncSinkNode(0) lazy val module = new Impl - class Impl extends LazyModuleImp(this) { + class Impl extends LazyRawModuleImp(this) { (node.in zip node.out) foreach { case ((in, edgeIn), (out, edgeOut)) => out := in.sync } diff --git a/src/main/scala/interrupts/NullIntSource.scala b/src/main/scala/interrupts/NullIntSource.scala index d906ac36fd9..ec2528aa70b 100644 --- a/src/main/scala/interrupts/NullIntSource.scala +++ b/src/main/scala/interrupts/NullIntSource.scala @@ -12,7 +12,7 @@ class NullIntSource(num: Int = 1, ports: Int = 1, sources: Int = 1)(implicit p: val intnode = IntSourceNode(IntSourcePortSimple(num, ports, sources)) lazy val module = new Impl - class Impl extends LazyModuleImp(this) { + class Impl extends LazyRawModuleImp(this) { intnode.out.foreach { case (o, _) => o.foreach { _ := false.B } } } } @@ -26,6 +26,6 @@ object NullIntSource { object NullIntSyncSource { def apply(num: Int = 1, ports: Int = 1, sources: Int = 1)(implicit p: Parameters): IntSyncOutwardNode = { - IntSyncCrossingSource() := NullIntSource(num, ports, sources) + IntSyncCrossingSource(alreadyRegistered = true) := NullIntSource(num, ports, sources) } } diff --git a/src/main/scala/interrupts/Xbar.scala b/src/main/scala/interrupts/Xbar.scala index 472fead6955..b2560106b61 100644 --- a/src/main/scala/interrupts/Xbar.scala +++ b/src/main/scala/interrupts/Xbar.scala @@ -19,7 +19,7 @@ class IntXbar()(implicit p: Parameters) extends LazyModule } lazy val module = new Impl - class Impl extends LazyModuleImp(this) { + class Impl extends LazyRawModuleImp(this) { val cat = intnode.in.map { case (i, e) => i.take(e.source.num) }.flatten intnode.out.foreach { case (o, _) => o := cat } } diff --git a/src/main/scala/prci/ClockBundles.scala b/src/main/scala/prci/ClockBundles.scala index 900e437a5af..0cf06cca6e5 100644 --- a/src/main/scala/prci/ClockBundles.scala +++ b/src/main/scala/prci/ClockBundles.scala @@ -5,7 +5,7 @@ import chisel3._ import freechips.rocketchip.util.RecordMap -class ClockBundle(val params: ClockBundleParameters) extends Bundle +class ClockBundle(val params: ClockBundleParameters = ClockBundleParameters()) extends Bundle { val clock = Output(Clock()) val reset = Output(Reset()) diff --git a/src/main/scala/prci/ClockDomain.scala b/src/main/scala/prci/ClockDomain.scala index 665372ca500..7bc10c69470 100644 --- a/src/main/scala/prci/ClockDomain.scala +++ b/src/main/scala/prci/ClockDomain.scala @@ -4,13 +4,15 @@ import chisel3._ import org.chipsalliance.cde.config.Parameters import freechips.rocketchip.diplomacy._ -abstract class Domain(implicit p: Parameters) extends LazyModule with HasDomainCrossing { +abstract class Domain(implicit p: Parameters) extends LazyModule with HasDomainCrossing +{ def clockBundle: ClockBundle lazy val module = new Impl class Impl extends LazyRawModuleImp(this) { childClock := clockBundle.clock childReset := clockBundle.reset + override def provideImplicitClockToLazyChildren = true // these are just for backwards compatibility with external devices // that were manually wiring themselves to the domain's clock/reset input: diff --git a/src/main/scala/prci/ClockGroup.scala b/src/main/scala/prci/ClockGroup.scala index ce2b8f98c97..f4c648bafe2 100644 --- a/src/main/scala/prci/ClockGroup.scala +++ b/src/main/scala/prci/ClockGroup.scala @@ -4,7 +4,7 @@ package freechips.rocketchip.prci import org.chipsalliance.cde.config.Parameters import freechips.rocketchip.diplomacy._ -case class ClockGroupNode(groupName: String)(implicit valName: ValName) +case class ClockGroupingNode(groupName: String)(implicit valName: ValName) extends MixedNexusNode(ClockGroupImp, ClockImp)( dFn = { _ => ClockSourceParameters() }, uFn = { seq => ClockGroupSinkParameters(name = groupName, members = seq) }) @@ -14,7 +14,7 @@ case class ClockGroupNode(groupName: String)(implicit valName: ValName) class ClockGroup(groupName: String)(implicit p: Parameters) extends LazyModule { - val node = ClockGroupNode(groupName) + val node = ClockGroupingNode(groupName) lazy val module = new Impl class Impl extends LazyRawModuleImp(this) { @@ -107,7 +107,7 @@ class FixedClockBroadcast(fixedClockOpt: Option[ClockParameters])(implicit p: Pa object FixedClockBroadcast { - def apply(fixedClockOpt: Option[ClockParameters])(implicit p: Parameters, valName: ValName) = LazyModule(new FixedClockBroadcast(fixedClockOpt)).node + def apply(fixedClockOpt: Option[ClockParameters] = None)(implicit p: Parameters, valName: ValName) = LazyModule(new FixedClockBroadcast(fixedClockOpt)).node } case class PRCIClockGroupNode()(implicit valName: ValName) diff --git a/src/main/scala/prci/ClockGroupDriver.scala b/src/main/scala/prci/ClockGroupDriver.scala deleted file mode 100644 index 63ff42f1e42..00000000000 --- a/src/main/scala/prci/ClockGroupDriver.scala +++ /dev/null @@ -1,46 +0,0 @@ -// See LICENSE.SiFive for license details. -package freechips.rocketchip.prci - -import chisel3._ -import org.chipsalliance.cde.config.Parameters -import freechips.rocketchip.diplomacy.{InModuleBody, ModuleValue, ValName} -import freechips.rocketchip.util.{RecordMap} - -/** Used to parameterize the creation of simple clock group drivers */ -case class ClockGroupDriverParameters( - num: Int = 1, - driveFn: ClockGroupDriver.DriveFn = ClockGroupDriver.driveFromImplicitClock -) { - def drive(node: ClockGroupEphemeralNode)(implicit p: Parameters, vn: ValName): ModuleValue[RecordMap[ClockBundle]] = { - driveFn(node, num, p, vn) - } -} - -object ClockGroupDriver { - type DriveFn = (ClockGroupEphemeralNode, Int, Parameters, ValName) => ModuleValue[RecordMap[ClockBundle]] - - /** Drive all members of all groups from the Chisel implicit clock */ - def driveFromImplicitClock: DriveFn = { (groups, num, p, vn) => - implicit val pp = p - val dummyClockGroupSourceNode: ClockGroupSourceNode = SimpleClockGroupSource(num) - groups :*= dummyClockGroupSourceNode - InModuleBody { RecordMap[ClockBundle]() } - } - - /** Drive all members of all groups from a flattened IO representation */ - def driveFromIOs: DriveFn = { (groups, num, p, vn) => - implicit val pp = p - val ioClockGroupSourceNode = ClockGroupSourceNode(List.fill(num) { ClockGroupSourceParameters() }) - groups :*= ioClockGroupSourceNode - InModuleBody { - val bundles = ioClockGroupSourceNode.out.map(_._1) - val elements = bundles.map(_.member.elements).flatten - val io = IO(Flipped(RecordMap(elements.map { case (name, data) => - name -> data.cloneType - }:_*))) - - elements.foreach { case (name, data) => io(name).foreach { data := _ } } - io.suggestName(vn.name) - } - } -} diff --git a/src/main/scala/prci/package.scala b/src/main/scala/prci/package.scala index e427add8d43..864126a03f2 100644 --- a/src/main/scala/prci/package.scala +++ b/src/main/scala/prci/package.scala @@ -9,6 +9,9 @@ package object prci type ClockInwardNode = InwardNodeHandle[ClockSourceParameters, ClockSinkParameters, ClockEdgeParameters, ClockBundle] type ClockOutwardNode = OutwardNodeHandle[ClockSourceParameters, ClockSinkParameters, ClockEdgeParameters, ClockBundle] type ClockNode = NodeHandle[ClockSourceParameters, ClockSinkParameters, ClockEdgeParameters, ClockBundle, ClockSourceParameters, ClockSinkParameters, ClockEdgeParameters, ClockBundle] + + type ClockGroupNode = NodeHandle[ClockGroupSourceParameters, ClockGroupSinkParameters, ClockGroupEdgeParameters, ClockGroupBundle, ClockGroupSourceParameters, ClockGroupSinkParameters, ClockGroupEdgeParameters, ClockGroupBundle] + def asyncMux[T](xType: ClockCrossingType, async: T, notasync: T): T = xType match { case _: AsynchronousCrossing => async case _ => notasync diff --git a/src/main/scala/rocket/CSR.scala b/src/main/scala/rocket/CSR.scala index 737f18673c4..87407e850fe 100644 --- a/src/main/scala/rocket/CSR.scala +++ b/src/main/scala/rocket/CSR.scala @@ -254,10 +254,10 @@ class CSRDecodeIO(implicit p: Parameters) extends CoreBundle { val virtual_system_illegal = Output(Bool()) } -class CSRFileIO(implicit p: Parameters) extends CoreBundle +class CSRFileIO(hasBeu: Boolean)(implicit p: Parameters) extends CoreBundle with HasCoreParameters { val ungated_clock = Input(Clock()) - val interrupts = Input(new CoreInterrupts()) + val interrupts = Input(new CoreInterrupts(hasBeu)) val hartid = Input(UInt(hartIdLen.W)) val rw = new Bundle { val addr = Input(UInt(CSR.ADDRSZ.W)) @@ -375,10 +375,11 @@ class VType(implicit p: Parameters) extends CoreBundle { class CSRFile( perfEventSets: EventSets = new EventSets(Seq()), customCSRs: Seq[CustomCSR] = Nil, - roccCSRs: Seq[CustomCSR] = Nil)(implicit p: Parameters) + roccCSRs: Seq[CustomCSR] = Nil, + hasBeu: Boolean = false)(implicit p: Parameters) extends CoreModule()(p) with HasCoreParameters { - val io = IO(new CSRFileIO { + val io = IO(new CSRFileIO(hasBeu) { val customCSRs = Vec(CSRFile.this.customCSRs.size, new CustomCSRIO) val roccCSRs = Vec(CSRFile.this.roccCSRs.size, new CustomCSRIO) }) diff --git a/src/main/scala/rocket/Frontend.scala b/src/main/scala/rocket/Frontend.scala index f6c0ad52b68..30297c5033c 100644 --- a/src/main/scala/rocket/Frontend.scala +++ b/src/main/scala/rocket/Frontend.scala @@ -61,9 +61,9 @@ class FrontendIO(implicit p: Parameters) extends CoreBundle()(p) { val progress = Output(Bool()) } -class Frontend(val icacheParams: ICacheParams, staticIdForMetadataUseOnly: Int)(implicit p: Parameters) extends LazyModule { +class Frontend(val icacheParams: ICacheParams, tileId: Int)(implicit p: Parameters) extends LazyModule { lazy val module = new FrontendModule(this) - val icache = LazyModule(new ICache(icacheParams, staticIdForMetadataUseOnly)) + val icache = LazyModule(new ICache(icacheParams, tileId)) val masterNode = icache.masterNode val slaveNode = icache.slaveNode val resetVectorSinkNode = BundleBridgeSink[UInt](Some(() => UInt(masterNode.edges.out.head.bundle.addressBits.W))) @@ -383,7 +383,7 @@ class FrontendModule(outer: Frontend) extends LazyModuleImp(outer) /** Mix-ins for constructing tiles that have an ICache-based pipeline frontend */ trait HasICacheFrontend extends CanHavePTW { this: BaseTile => val module: HasICacheFrontendModule - val frontend = LazyModule(new Frontend(tileParams.icache.get, staticIdForMetadataUseOnly)) + val frontend = LazyModule(new Frontend(tileParams.icache.get, tileId)) tlMasterXbar.node := TLWidthWidget(tileParams.icache.get.rowBits/8) := frontend.masterNode connectTLSlave(frontend.slaveNode, tileParams.core.fetchBytes) frontend.icache.hartIdSinkNodeOpt.foreach { _ := hartIdNexusNode } diff --git a/src/main/scala/rocket/HellaCache.scala b/src/main/scala/rocket/HellaCache.scala index 7360ab89fc0..41c8bdfdfe8 100644 --- a/src/main/scala/rocket/HellaCache.scala +++ b/src/main/scala/rocket/HellaCache.scala @@ -188,17 +188,17 @@ class HellaCacheIO(implicit p: Parameters) extends CoreBundle()(p) { /** Base classes for Diplomatic TL2 HellaCaches */ -abstract class HellaCache(staticIdForMetadataUseOnly: Int)(implicit p: Parameters) extends LazyModule +abstract class HellaCache(tileId: Int)(implicit p: Parameters) extends LazyModule with HasNonDiplomaticTileParameters { protected val cfg = tileParams.dcache.get protected def cacheClientParameters = cfg.scratch.map(x => Seq()).getOrElse(Seq(TLMasterParameters.v1( - name = s"Core ${staticIdForMetadataUseOnly} DCache", + name = s"Core ${tileId} DCache", sourceId = IdRange(0, 1 max cfg.nMSHRs), supportsProbe = TransferSizes(cfg.blockBytes, cfg.blockBytes)))) protected def mmioClientParameters = Seq(TLMasterParameters.v1( - name = s"Core ${staticIdForMetadataUseOnly} DCache MMIO", + name = s"Core ${tileId} DCache MMIO", sourceId = IdRange(firstMMIO, firstMMIO + cfg.nMMIOs), requestFifo = true)) @@ -254,9 +254,9 @@ case object BuildHellaCache extends Field[BaseTile => Parameters => HellaCache]( object HellaCacheFactory { def apply(tile: BaseTile)(p: Parameters): HellaCache = { if (tile.tileParams.dcache.get.nMSHRs == 0) - new DCache(tile.staticIdForMetadataUseOnly, tile.crossing)(p) + new DCache(tile.tileId, tile.crossing)(p) else - new NonBlockingDCache(tile.staticIdForMetadataUseOnly)(p) + new NonBlockingDCache(tile.tileId)(p) } } diff --git a/src/main/scala/rocket/RocketCore.scala b/src/main/scala/rocket/RocketCore.scala index 65f8c73234a..ff6e1e37aea 100644 --- a/src/main/scala/rocket/RocketCore.scala +++ b/src/main/scala/rocket/RocketCore.scala @@ -112,9 +112,34 @@ class RocketCustomCSRs(implicit p: Parameters) extends CustomCSRs with HasRocket override def decls = super.decls :+ marchid :+ mvendorid :+ mimpid } +class CoreInterrupts(val hasBeu: Boolean)(implicit p: Parameters) extends TileInterrupts()(p) { + val buserror = Option.when(hasBeu)(Bool()) +} + +trait HasRocketCoreIO extends HasRocketCoreParameters { + implicit val p: Parameters + def nTotalRoCCCSRs: Int + val io = IO(new CoreBundle()(p) { + val hartid = Input(UInt(hartIdLen.W)) + val reset_vector = Input(UInt(resetVectorLen.W)) + val interrupts = Input(new CoreInterrupts(tileParams.asInstanceOf[RocketTileParams].beuAddr.isDefined)) + val imem = new FrontendIO + val dmem = new HellaCacheIO + val ptw = Flipped(new DatapathPTWIO()) + val fpu = Flipped(new FPUCoreIO()) + val rocc = Flipped(new RoCCCoreIO(nTotalRoCCCSRs)) + val trace = Output(new TraceBundle) + val bpwatch = Output(Vec(coreParams.nBreakpoints, new BPWatch(coreParams.retireWidth))) + val cease = Output(Bool()) + val wfi = Output(Bool()) + val traceStall = Input(Bool()) + }) +} + + class Rocket(tile: RocketTile)(implicit p: Parameters) extends CoreModule()(p) with HasRocketCoreParameters - with HasCoreIO { + with HasRocketCoreIO { def nTotalRoCCCSRs = tile.roccCSRs.flatten.size val clock_en_reg = RegInit(true.B) @@ -291,7 +316,7 @@ class Rocket(tile: RocketTile)(implicit p: Parameters) extends CoreModule()(p) val ctrl_killd = Wire(Bool()) val id_npc = (ibuf.io.pc.asSInt + ImmGen(IMM_UJ, id_inst(0))).asUInt - val csr = Module(new CSRFile(perfEvents, coreParams.customCSRs.decls, tile.roccCSRs.flatten)) + val csr = Module(new CSRFile(perfEvents, coreParams.customCSRs.decls, tile.roccCSRs.flatten, tile.rocketParams.beuAddr.isDefined)) val id_csr_en = id_ctrl.csr.isOneOf(CSR.S, CSR.C, CSR.W) val id_system_insn = id_ctrl.csr === CSR.I val id_csr_ren = id_ctrl.csr.isOneOf(CSR.S, CSR.C) && id_expanded_inst(0).rs1 === 0.U diff --git a/src/main/scala/subsystem/Attachable.scala b/src/main/scala/subsystem/Attachable.scala index 7809280a110..06f2269421f 100644 --- a/src/main/scala/subsystem/Attachable.scala +++ b/src/main/scala/subsystem/Attachable.scala @@ -4,7 +4,7 @@ package freechips.rocketchip.subsystem import org.chipsalliance.cde.config.Parameters import freechips.rocketchip.diplomacy.{LazyModule, LazyScope} -import freechips.rocketchip.prci.ClockGroupEphemeralNode +import freechips.rocketchip.prci.ClockGroupNode import freechips.rocketchip.tilelink.TLBusWrapper import freechips.rocketchip.util.{Location, LocationMap} @@ -23,13 +23,14 @@ trait LazyScopeWithParameters extends LazyScope { this: LazyModule => /** Layers of hierarchy with this trait contain attachment points for neworks of power, clock, reset, and interrupt resources */ trait HasPRCILocations extends LazyScopeWithParameters { this: LazyModule => - implicit val asyncClockGroupsNode: ClockGroupEphemeralNode + val allClockGroupsNode: ClockGroupNode val ibus: InterruptBusWrapper val anyLocationMap = LocationMap.empty[Any] } /** Layers of hierarchy with this trait contain attachment points for TileLink interfaces */ trait HasTileLinkLocations extends HasPRCILocations { this: LazyModule => + val busContextName: String val tlBusWrapperLocationMap = LocationMap.empty[TLBusWrapper] def locateTLBusWrapper(location: Location[TLBusWrapper]): TLBusWrapper = locateTLBusWrapper(location.name) def locateTLBusWrapper(name: String): TLBusWrapper = tlBusWrapperLocationMap(Location[TLBusWrapper](name)) diff --git a/src/main/scala/subsystem/BankedL2Params.scala b/src/main/scala/subsystem/BankedCoherenceParams.scala similarity index 92% rename from src/main/scala/subsystem/BankedL2Params.scala rename to src/main/scala/subsystem/BankedCoherenceParams.scala index 402dd537804..84a7d015c37 100644 --- a/src/main/scala/subsystem/BankedL2Params.scala +++ b/src/main/scala/subsystem/BankedCoherenceParams.scala @@ -14,7 +14,7 @@ import CoherenceManagerWrapper._ /** Global cache coherence granularity, which applies to all caches, for now. */ case object CacheBlockBytes extends Field[Int](64) -/** L2 Broadcast Hub configuration */ +/** LLC Broadcast Hub configuration */ case object BroadcastKey extends Field(BroadcastParams()) case class BroadcastParams( @@ -23,10 +23,11 @@ case class BroadcastParams( controlAddress: Option[BigInt] = None, filterFactory: TLBroadcast.ProbeFilterFactory = BroadcastFilter.factory) -/** L2 memory subsystem configuration */ -case object BankedL2Key extends Field(BankedL2Params()) +/** Coherence manager configuration */ +case object SubsystemBankedCoherenceKey extends Field(BankedCoherenceParams()) +case class ClusterBankedCoherenceKey(clusterId: Int) extends Field(BankedCoherenceParams(nBanks=0)) -case class BankedL2Params( +case class BankedCoherenceParams( nBanks: Int = 1, coherenceManager: CoherenceManagerInstantiationFn = broadcastManager ) { diff --git a/src/main/scala/subsystem/BaseSubsystem.scala b/src/main/scala/subsystem/BaseSubsystem.scala index 926e1d22923..347466709f1 100644 --- a/src/main/scala/subsystem/BaseSubsystem.scala +++ b/src/main/scala/subsystem/BaseSubsystem.scala @@ -2,6 +2,7 @@ package freechips.rocketchip.subsystem +import chisel3.{Flipped, IO} import chisel3.util._ import org.chipsalliance.cde.config.{Field, Parameters} import freechips.rocketchip.diplomacy._ @@ -9,8 +10,7 @@ import freechips.rocketchip.prci._ import freechips.rocketchip.tilelink.TLBusWrapper import freechips.rocketchip.util._ -case object SubsystemDriveAsyncClockGroupsKey extends Field[Option[ClockGroupDriverParameters]](Some(ClockGroupDriverParameters(1))) -case object AsyncClockGroupsKey extends Field[() => ClockGroupEphemeralNode](() => ClockGroupEphemeralNode()(ValName("clock_sources"))) +case object SubsystemDriveClockGroupsFromIO extends Field[Boolean](true) case class TLNetworkTopologyLocated(where: HierarchicalLocation) extends Field[Seq[CanInstantiateWithinContextThatHasTileLinkLocations with CanConnectWithinContextThatHasTileLinkLocations]] case class TLManagerViewpointLocated(where: HierarchicalLocation) extends Field[Location[TLBusWrapper]](SBUS) @@ -26,7 +26,7 @@ abstract class BareSubsystem(implicit p: Parameters) extends LazyModule with Bin lazy val json = JSON(bindingTree) } -abstract class BareSubsystemModuleImp[+L <: BareSubsystem](_outer: L) extends LazyModuleImp(_outer) { +abstract class BareSubsystemModuleImp[+L <: BareSubsystem](_outer: L) extends LazyRawModuleImp(_outer) { val outer = _outer ElaborationArtefacts.add("graphml", outer.graphML) ElaborationArtefacts.add("dts", outer.dts) @@ -47,11 +47,22 @@ case object SubsystemResetSchemeKey extends Field[SubsystemResetScheme](ResetSyn */ trait HasConfigurablePRCILocations { this: HasPRCILocations => val ibus = LazyModule(new InterruptBusWrapper) - implicit val asyncClockGroupsNode = p(AsyncClockGroupsKey)() - val clock_sources: ModuleValue[RecordMap[ClockBundle]] = - p(SubsystemDriveAsyncClockGroupsKey) - .map(_.drive(asyncClockGroupsNode)) - .getOrElse(InModuleBody { RecordMap[ClockBundle]() }) + val allClockGroupsNode = ClockGroupIdentityNode() + val io_clocks = if (p(SubsystemDriveClockGroupsFromIO)) { + val aggregator = ClockGroupAggregator() + val source = ClockGroupSourceNode(Seq(ClockGroupSourceParameters())) + allClockGroupsNode :*= aggregator := source + Some(InModuleBody { + val elements = source.out.map(_._1.member.elements).flatten + val io = IO(Flipped(RecordMap(elements.map { case (name, data) => + name -> data.cloneType + }:_*))) + elements.foreach { case (name, data) => io(name).foreach { data := _ } } + io + }) + } else { + None + } } /** Look up the topology configuration for the TL buses located within this layer of the hierarchy */ @@ -77,9 +88,11 @@ abstract class BaseSubsystem(val location: HierarchicalLocation = InSubsystem) { override val module: BaseSubsystemModuleImp[BaseSubsystem] + val busContextName = "subsystem" + // TODO must there really always be an "sbus"? val sbus = tlBusWrapperLocationMap(SBUS) - tlBusWrapperLocationMap.lift(SBUS).map { _.clockGroupNode := asyncClockGroupsNode } + tlBusWrapperLocationMap.lift(SBUS).map { _.clockGroupNode := allClockGroupsNode } // TODO: Preserve legacy implicit-clock behavior for IBUS for now. If binding // a PLIC to the CBUS, ensure it is synchronously coupled to the SBUS. diff --git a/src/main/scala/subsystem/BusTopology.scala b/src/main/scala/subsystem/BusTopology.scala index 239a016647e..a9d77b5b127 100644 --- a/src/main/scala/subsystem/BusTopology.scala +++ b/src/main/scala/subsystem/BusTopology.scala @@ -23,12 +23,16 @@ case object MemoryBusKey extends Field[MemoryBusParams] // dynamically-configured topologies. class TLBusWrapperLocation(name: String) extends Location[TLBusWrapper](name) -case object SBUS extends TLBusWrapperLocation("subsystem_sbus") -case object PBUS extends TLBusWrapperLocation("subsystem_pbus") -case object FBUS extends TLBusWrapperLocation("subsystem_fbus") -case object MBUS extends TLBusWrapperLocation("subsystem_mbus") -case object CBUS extends TLBusWrapperLocation("subsystem_cbus") -case object L2 extends TLBusWrapperLocation("subsystem_l2") +case object SBUS extends TLBusWrapperLocation("sbus") +case object PBUS extends TLBusWrapperLocation("pbus") +case object FBUS extends TLBusWrapperLocation("fbus") +case object MBUS extends TLBusWrapperLocation("mbus") +case object CBUS extends TLBusWrapperLocation("cbus") +case object COH extends TLBusWrapperLocation("coh") +case class CSBUS(clusterId: Int) extends TLBusWrapperLocation(s"csbus$clusterId") +case class CMBUS(clusterId: Int) extends TLBusWrapperLocation(s"cmbus$clusterId") +case class CCBUS(clusterId: Int) extends TLBusWrapperLocation(s"ccbus$clusterId") +case class CCOH (clusterId: Int) extends TLBusWrapperLocation(s"ccoh$clusterId") /** Parameterizes the subsystem in terms of optional clock-crossings * that are insertable between some of the five traditional tilelink bus wrappers. @@ -89,20 +93,40 @@ case class HierarchicalBusTopologyParams( /** Parameterization of a topology containing a banked coherence manager and a bus for attaching memory devices. */ case class CoherentBusTopologyParams( - sbus: SystemBusParams, // TODO remove this after better width propagation mbus: MemoryBusParams, - l2: BankedL2Params, + coherence: BankedCoherenceParams, sbusToMbusXType: ClockCrossingType = NoCrossing, driveMBusClockFromSBus: Boolean = true ) extends TLBusWrapperTopology( - instantiations = (if (l2.nBanks == 0) Nil else List( + instantiations = (if (coherence.nBanks == 0) Nil else List( (MBUS, mbus), - (L2, CoherenceManagerWrapperParams(mbus.blockBytes, mbus.beatBytes, l2.nBanks, L2.name, sbus.dtsFrequency)(l2.coherenceManager)))), - connections = if (l2.nBanks == 0) Nil else List( - (SBUS, L2, TLBusWrapperConnection(driveClockFromMaster = Some(true), nodeBinding = BIND_STAR)()), - (L2, MBUS, TLBusWrapperConnection.crossTo( + (COH, CoherenceManagerWrapperParams(mbus.blockBytes, mbus.beatBytes, coherence.nBanks, COH.name)(coherence.coherenceManager)))), + connections = if (coherence.nBanks == 0) Nil else List( + (SBUS, COH, TLBusWrapperConnection(driveClockFromMaster = Some(true), nodeBinding = BIND_STAR)()), + (COH, MBUS, TLBusWrapperConnection.crossTo( xType = sbusToMbusXType, driveClockFromMaster = if (driveMBusClockFromSBus) Some(true) else None, nodeBinding = BIND_QUERY)) ) ) + +case class ClusterBusTopologyParams( + clusterId: Int, + csbus: SystemBusParams, + ccbus: PeripheryBusParams, + coherence: BankedCoherenceParams +) extends TLBusWrapperTopology( + instantiations = List( + (CSBUS(clusterId), csbus), + (CCBUS(clusterId), ccbus)) ++ (if (coherence.nBanks == 0) Nil else List( + (CMBUS(clusterId), csbus), + (CCOH (clusterId), CoherenceManagerWrapperParams(csbus.blockBytes, csbus.beatBytes, coherence.nBanks, CCOH(clusterId).name)(coherence.coherenceManager)))), + connections = if (coherence.nBanks == 0) Nil else List( + (CSBUS(clusterId), CCOH (clusterId), TLBusWrapperConnection(driveClockFromMaster = Some(true), nodeBinding = BIND_STAR)()), + (CCOH (clusterId), CMBUS(clusterId), TLBusWrapperConnection.crossTo( + xType = NoCrossing, + driveClockFromMaster = Some(true), + nodeBinding = BIND_QUERY)) + ) +) + diff --git a/src/main/scala/subsystem/Cluster.scala b/src/main/scala/subsystem/Cluster.scala new file mode 100644 index 00000000000..7e2ca886a17 --- /dev/null +++ b/src/main/scala/subsystem/Cluster.scala @@ -0,0 +1,233 @@ +package freechips.rocketchip.subsystem + +import chisel3._ +import chisel3.util._ + +import org.chipsalliance.cde.config.{Field, Parameters} +import freechips.rocketchip.diplomacy._ +import freechips.rocketchip.interrupts._ +import freechips.rocketchip.prci._ +import freechips.rocketchip.tile.{RocketTile, NMI, TraceBundle} +import freechips.rocketchip.subsystem._ +import freechips.rocketchip.tilelink._ +import freechips.rocketchip.devices.debug.{TLDebugModule} +import freechips.rocketchip.devices.tilelink._ +import freechips.rocketchip.util._ +import scala.collection.immutable.SortedMap + +case class ClustersLocated(loc: HierarchicalLocation) extends Field[Seq[CanAttachCluster]](Nil) + +case class ClusterParams( + val clusterId: Int, + val clockSinkParams: ClockSinkParameters = ClockSinkParameters() +) extends HierarchicalElementParams { + val baseName = "cluster" + val uniqueName = s"${baseName}_$clusterId" + def instantiate(crossing: HierarchicalElementCrossingParamsLike, lookup: LookupByClusterIdImpl)(implicit p: Parameters): Cluster = { + new Cluster(this, crossing.crossingType, lookup) + } +} + +class Cluster( + val thisClusterParams: ClusterParams, + crossing: ClockCrossingType, + lookup: LookupByClusterIdImpl)(implicit p: Parameters) extends BaseHierarchicalElement(crossing)(p) + with Attachable + with HasConfigurableTLNetworkTopology + with InstantiatesHierarchicalElements + with HasHierarchicalElements +{ + val busContextName = thisClusterParams.baseName + lazy val clusterId = thisClusterParams.clusterId + lazy val location = InCluster(clusterId) + + lazy val allClockGroupsNode = ClockGroupIdentityNode() + + val csbus = tlBusWrapperLocationMap(CSBUS(clusterId)) // like the sbus in the base subsystem + val ccbus = tlBusWrapperLocationMap(CCBUS(clusterId)) // like the cbus in the base subsystem + val cmbus = tlBusWrapperLocationMap.lift(CMBUS(clusterId)).getOrElse(csbus) + + csbus.clockGroupNode := allClockGroupsNode + ccbus.clockGroupNode := allClockGroupsNode + + val slaveNode = ccbus.inwardNode + val masterNode = cmbus.outwardNode + + + + lazy val ibus = LazyModule(new InterruptBusWrapper) + ibus.clockNode := csbus.fixedClockNode + + def msipDomain = this + def meipDomain = this + def seipDomain = this + lazy val msipNodes = totalTileIdList.map { i => (i, IntIdentityNode()) }.to(SortedMap) + lazy val meipNodes = totalTileIdList.map { i => (i, IntIdentityNode()) }.to(SortedMap) + lazy val seipNodes = totalTileIdList.map { i => (i, IntIdentityNode()) }.to(SortedMap) + lazy val tileToPlicNodes = totalTileIdList.map { i => (i, IntIdentityNode()) }.to(SortedMap) + lazy val debugNodes = totalTileIdList.map { i => (i, IntSyncIdentityNode()) }.to(SortedMap) + lazy val nmiNodes = totalTiles.filter { case (i,t) => t.tileParams.core.useNMI } + .mapValues(_ => BundleBridgeIdentityNode[NMI]()).to(SortedMap) + lazy val tileHartIdNodes = totalTileIdList.map { i => (i, BundleBridgeIdentityNode[UInt]()) }.to(SortedMap) + lazy val tileResetVectorNodes = totalTileIdList.map { i => (i, BundleBridgeIdentityNode[UInt]()) }.to(SortedMap) + lazy val traceCoreNodes = totalTileIdList.map { i => (i, BundleBridgeIdentityNode[TraceCoreInterface]()) }.to(SortedMap) + lazy val traceNodes = totalTileIdList.map { i => (i, BundleBridgeIdentityNode[TraceBundle]()) }.to(SortedMap) + + // TODO fix: shouldn't need to connect dummy notifications + tileHaltXbarNode := NullIntSource() + tileWFIXbarNode := NullIntSource() + tileCeaseXbarNode := NullIntSource() + + override lazy val module = new ClusterModuleImp(this) +} + +class ClusterModuleImp(outer: Cluster) extends BaseHierarchicalElementModuleImp[Cluster](outer) + +case class InCluster(id: Int) extends HierarchicalLocation(s"Cluster$id") + +class ClusterPRCIDomain( + clockSinkParams: ClockSinkParameters, + crossingParams: HierarchicalElementCrossingParamsLike, + clusterParams: ClusterParams, + lookup: LookupByClusterIdImpl) + (implicit p: Parameters) extends HierarchicalElementPRCIDomain[Cluster](clockSinkParams, crossingParams) +{ + val element = element_reset_domain { + LazyModule(clusterParams.instantiate(crossingParams, lookup)) + } + // Nothing should depend on the clocks coming from clockNode anyways + clockNode := element.csbus.fixedClockNode +} + + +trait CanAttachCluster { + type ClusterContextType <: DefaultHierarchicalElementContextType + + def clusterParams: ClusterParams + def crossingParams: HierarchicalElementCrossingParamsLike + + def instantiate(allClusterParams: Seq[ClusterParams], instantiatedClusters: SortedMap[Int, ClusterPRCIDomain])(implicit p: Parameters): ClusterPRCIDomain = { + val clockSinkParams = clusterParams.clockSinkParams.copy(name = Some(clusterParams.uniqueName)) + val cluster_prci_domain = LazyModule(new ClusterPRCIDomain( + clockSinkParams, crossingParams, clusterParams, PriorityMuxClusterIdFromSeq(allClusterParams))) + cluster_prci_domain + } + + def connect(domain: ClusterPRCIDomain, context: ClusterContextType): Unit = { + connectMasterPorts(domain, context) + connectSlavePorts(domain, context) + connectInterrupts(domain, context) + connectPRC(domain, context) + connectOutputNotifications(domain, context) + connectInputConstants(domain, context) + connectTrace(domain, context) + } + + def connectMasterPorts(domain: ClusterPRCIDomain, context: Attachable): Unit = { + implicit val p = context.p + val dataBus = context.locateTLBusWrapper(crossingParams.master.where) + dataBus.coupleFrom(clusterParams.baseName) { bus => + bus :=* crossingParams.master.injectNode(context) :=* domain.crossMasterPort(crossingParams.crossingType) + } + } + def connectSlavePorts(domain: ClusterPRCIDomain, context: Attachable): Unit = { + implicit val p = context.p + val controlBus = context.locateTLBusWrapper(crossingParams.slave.where) + controlBus.coupleTo(clusterParams.baseName) { bus => + domain.crossSlavePort(crossingParams.crossingType) :*= crossingParams.slave.injectNode(context) :*= TLWidthWidget(controlBus.beatBytes) :*= bus + } + } + def connectInterrupts(domain: ClusterPRCIDomain, context: ClusterContextType): Unit = { + implicit val p = context.p + + domain.element.debugNodes.foreach { case (hartid, node) => + node := context.debugNodes(hartid) + } + + domain.element.msipNodes.foreach { case (hartid, node) => context.msipDomain { + domain.crossIntIn(crossingParams.crossingType, node) := context.msipNodes(hartid) + }} + + domain.element.meipNodes.foreach { case (hartid, node) => context.meipDomain { + domain.crossIntIn(crossingParams.crossingType, node) := context.meipNodes(hartid) + }} + + domain.element.seipNodes.foreach { case (hartid, node) => context.seipDomain { + domain.crossIntIn(crossingParams.crossingType, node) := context.seipNodes(hartid) + }} + + domain.element.tileToPlicNodes.foreach { case (hartid, node) => + FlipRendering { implicit p => + context.tileToPlicNodes(hartid) :=* domain.crossIntOut(crossingParams.crossingType, node) } + } + context.ibus.fromSync :=* domain.crossIntOut(crossingParams.crossingType, domain.element.ibus.toPLIC) + + domain.element.nmiNodes.foreach { case (hartid, node) => + node := context.nmiNodes(hartid) + } + } + + def connectPRC(domain: ClusterPRCIDomain, context: ClusterContextType): Unit = { + implicit val p = context.p + domain.element.allClockGroupsNode :*= context.allClockGroupsNode + domain { + domain.element_reset_domain.clockNode := crossingParams.resetCrossingType.injectClockNode := domain.clockNode + } + } + + def connectOutputNotifications(domain: ClusterPRCIDomain, context: ClusterContextType): Unit = { + implicit val p = context.p + context.tileHaltXbarNode :=* domain.crossIntOut(NoCrossing, domain.element.tileHaltXbarNode) + context.tileWFIXbarNode :=* domain.crossIntOut(NoCrossing, domain.element.tileWFIXbarNode) + context.tileCeaseXbarNode :=* domain.crossIntOut(NoCrossing, domain.element.tileCeaseXbarNode) + + } + + def connectInputConstants(domain: ClusterPRCIDomain, context: ClusterContextType): Unit = { + implicit val p = context.p + val tlBusToGetPrefixFrom = context.locateTLBusWrapper(crossingParams.mmioBaseAddressPrefixWhere) + domain.element.tileHartIdNodes.foreach { case (hartid, node) => + node := context.tileHartIdNodes(hartid) + } + domain.element.tileResetVectorNodes.foreach { case (hartid, node) => + node := context.tileResetVectorNodes(hartid) + } + } + + def connectTrace(domain: ClusterPRCIDomain, context: ClusterContextType): Unit = { + implicit val p = context.p + domain.element.traceNodes.foreach { case (hartid, node) => + val traceNexusNode = BundleBridgeBlockDuringReset[TraceBundle]( + resetCrossingType = crossingParams.resetCrossingType) + context.traceNodes(hartid) := traceNexusNode := node + } + domain.element.traceCoreNodes.foreach { case (hartid, node) => + val traceCoreNexusNode = BundleBridgeBlockDuringReset[TraceCoreInterface]( + resetCrossingType = crossingParams.resetCrossingType) + context.traceCoreNodes(hartid) :*= traceCoreNexusNode := node + } + } +} + +case class ClusterAttachParams( + clusterParams: ClusterParams, + crossingParams: HierarchicalElementCrossingParamsLike +) extends CanAttachCluster + +case class CloneClusterAttachParams( + sourceClusterId: Int, + cloneParams: CanAttachCluster +) extends CanAttachCluster { + def clusterParams = cloneParams.clusterParams + def crossingParams = cloneParams.crossingParams + + override def instantiate(allClusterParams: Seq[ClusterParams], instantiatedClusters: SortedMap[Int, ClusterPRCIDomain])(implicit p: Parameters): ClusterPRCIDomain = { + require(instantiatedClusters.contains(sourceClusterId)) + val clockSinkParams = clusterParams.clockSinkParams.copy(name = Some(clusterParams.uniqueName)) + val cluster_prci_domain = CloneLazyModule( + new ClusterPRCIDomain(clockSinkParams, crossingParams, clusterParams, PriorityMuxClusterIdFromSeq(allClusterParams)), + instantiatedClusters(sourceClusterId) + ) + cluster_prci_domain + } +} diff --git a/src/main/scala/subsystem/Configs.scala b/src/main/scala/subsystem/Configs.scala index a9dbf4307bb..57bec6d4cef 100644 --- a/src/main/scala/subsystem/Configs.scala +++ b/src/main/scala/subsystem/Configs.scala @@ -16,7 +16,8 @@ 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(TilesLocated(InSubsystem)).map(_.tileParams.hartId) :+ 0).max+1) + case MaxHartIdBits => log2Up((site(PossibleTileLocations).flatMap(loc => site(TilesLocated(loc))) + .map(_.tileParams.tileId) :+ 0).max+1) // Interconnect parameters case SystemBusKey => SystemBusParams( beatBytes = site(XLen)/8, @@ -24,6 +25,7 @@ class BaseSubsystemConfig extends Config ((site, here, up) => { case ControlBusKey => PeripheryBusParams( beatBytes = site(XLen)/8, blockBytes = site(CacheBlockBytes), + dtsFrequency = Some(100000000), // Default to 100 MHz cbus clock errorDevice = Some(BuiltInErrorDeviceParams( errorParams = DevNullParams(List(AddressSet(0x3000, 0xfff)), maxAtomic=site(XLen)/8, maxTransfer=4096)))) case PeripheryBusKey => PeripheryBusParams( @@ -38,11 +40,12 @@ class BaseSubsystemConfig extends Config ((site, here, up) => { blockBytes = site(CacheBlockBytes)) // Additional device Parameters case BootROMLocated(InSubsystem) => Some(BootROMParams(contentFileName = "./bootrom/bootrom.img")) - case SubsystemExternalResetVectorKey => false + case HasTilesExternalResetVectorKey => false case DebugModuleKey => Some(DefaultDebugModuleParams(site(XLen))) case CLINTKey => Some(CLINTParams()) case PLICKey => Some(PLICParams()) case TilesLocated(InSubsystem) => Nil + case PossibleTileLocations => Seq(InSubsystem) }) /* Composable partial function Configs to set individual parameters */ @@ -80,21 +83,20 @@ class WithCoherentBusTopology extends Config((site, here, up) => { fbusToSbusXType = site(FbusToSbusXTypeKey)), driveClocksFromSBus = site(DriveClocksFromSBus)), CoherentBusTopologyParams( - sbus = site(SystemBusKey), mbus = site(MemoryBusKey), - l2 = site(BankedL2Key), + coherence = site(SubsystemBankedCoherenceKey), sbusToMbusXType = site(SbusToMbusXTypeKey), driveMBusClockFromSBus = site(DriveClocksFromSBus))) }) class WithNBigCores( n: Int, - overrideIdOffset: Option[Int] = None, - crossing: RocketCrossingParams = RocketCrossingParams() + location: HierarchicalLocation, + crossing: RocketCrossingParams, ) extends Config((site, here, up) => { - case TilesLocated(InSubsystem) => { - val prev = up(TilesLocated(InSubsystem), site) - val idOffset = overrideIdOffset.getOrElse(prev.size) + case TilesLocated(`location`) => { + val prev = up(TilesLocated(`location`), site) + val idOffset = up(NumTiles) val big = RocketTileParams( core = RocketCoreParams(mulDiv = Some(MulDivParams( mulUnroll = 8, @@ -108,20 +110,31 @@ class WithNBigCores( rowBits = site(SystemBusKey).beatBits, blockBytes = site(CacheBlockBytes)))) List.tabulate(n)(i => RocketTileAttachParams( - big.copy(hartId = i + idOffset), + big.copy(tileId = i + idOffset), crossing )) ++ prev } -}) + case NumTiles => up(NumTiles) + n +}) { + def this(n: Int, location: HierarchicalLocation = InSubsystem) = this(n, location, RocketCrossingParams( + master = HierarchicalElementMasterPortParams.locationDefault(location), + slave = HierarchicalElementSlavePortParams.locationDefault(location), + mmioBaseAddressPrefixWhere = location match { + case InSubsystem => CBUS + case InCluster(clusterId) => CCBUS(clusterId) + } + )) +} + + class WithNMedCores( n: Int, - overrideIdOffset: Option[Int] = None, - crossing: RocketCrossingParams = RocketCrossingParams() + crossing: RocketCrossingParams = RocketCrossingParams(), ) extends Config((site, here, up) => { case TilesLocated(InSubsystem) => { val prev = up(TilesLocated(InSubsystem), site) - val idOffset = overrideIdOffset.getOrElse(prev.size) + val idOffset = up(NumTiles) val med = RocketTileParams( core = RocketCoreParams(fpu = None), btb = None, @@ -141,20 +154,20 @@ class WithNMedCores( nTLBWays = 4, blockBytes = site(CacheBlockBytes)))) List.tabulate(n)(i => RocketTileAttachParams( - med.copy(hartId = i + idOffset), + med.copy(tileId = i + idOffset), crossing )) ++ prev } + case NumTiles => up(NumTiles) + n }) class WithNSmallCores( n: Int, - overrideIdOffset: Option[Int] = None, crossing: RocketCrossingParams = RocketCrossingParams() ) extends Config((site, here, up) => { case TilesLocated(InSubsystem) => { val prev = up(TilesLocated(InSubsystem), site) - val idOffset = overrideIdOffset.getOrElse(prev.size) + val idOffset = up(NumTiles) val small = RocketTileParams( core = RocketCoreParams(useVM = false, fpu = None), btb = None, @@ -174,10 +187,11 @@ class WithNSmallCores( nTLBWays = 4, blockBytes = site(CacheBlockBytes)))) List.tabulate(n)(i => RocketTileAttachParams( - small.copy(hartId = i + idOffset), + small.copy(tileId = i + idOffset), crossing )) ++ prev } + case NumTiles => up(NumTiles) + n }) class With1TinyCore extends Config((site, here, up) => { @@ -210,13 +224,38 @@ class With1TinyCore extends Config((site, here, up) => { tiny, RocketCrossingParams( crossingType = SynchronousCrossing(), - master = TileMasterPortParams()) + master = HierarchicalElementMasterPortParams()) )) } + case NumTiles => 1 + case ClustersLocated(_) => Nil +}) + +class WithCluster( + clusterId: Int, + location: HierarchicalLocation = InSubsystem, + crossing: RocketCrossingParams = RocketCrossingParams() // TODO make this not rocket +) extends Config((site, here, up) => { + case ClustersLocated(`location`) => up(ClustersLocated(location)) :+ ClusterAttachParams( + ClusterParams(clusterId = clusterId), + crossing) + case TLNetworkTopologyLocated(InCluster(`clusterId`)) => List( + ClusterBusTopologyParams( + clusterId = clusterId, + csbus = site(SystemBusKey), + ccbus = site(ControlBusKey).copy(errorDevice = None), + coherence = site(ClusterBankedCoherenceKey(clusterId)) + ) + ) + case PossibleTileLocations => up(PossibleTileLocations) :+ InCluster(clusterId) +}) + +class WithClusterBanks(clusterId: Int, nBanks: Int = 1) extends Config((site, here, up) => { + case ClusterBankedCoherenceKey(`clusterId`) => up(ClusterBankedCoherenceKey(clusterId)).copy(nBanks=nBanks) }) class WithNBanks(n: Int) extends Config((site, here, up) => { - case BankedL2Key => up(BankedL2Key, site).copy(nBanks = n) + case SubsystemBankedCoherenceKey => up(SubsystemBankedCoherenceKey, site).copy(nBanks = n) }) class WithNTrackersPerBank(n: Int) extends Config((site, here, up) => { @@ -225,7 +264,7 @@ class WithNTrackersPerBank(n: Int) extends Config((site, here, up) => { // This is the number of icache sets for all Rocket tiles class WithL1ICacheSets(sets: Int) extends Config((site, here, up) => { - case TilesLocated(InSubsystem) => up(TilesLocated(InSubsystem), site) map { + case TilesLocated(location) => up(TilesLocated(location), site) map { case tp: RocketTileAttachParams => tp.copy(tileParams = tp.tileParams.copy( icache = tp.tileParams.icache.map(_.copy(nSets = sets)))) case t => t @@ -234,7 +273,7 @@ class WithL1ICacheSets(sets: Int) extends Config((site, here, up) => { // This is the number of icache sets for all Rocket tiles class WithL1DCacheSets(sets: Int) extends Config((site, here, up) => { - case TilesLocated(InSubsystem) => up(TilesLocated(InSubsystem), site) map { + case TilesLocated(location) => up(TilesLocated(location), site) map { case tp: RocketTileAttachParams => tp.copy(tileParams = tp.tileParams.copy( dcache = tp.tileParams.dcache.map(_.copy(nSets = sets)))) case t => t @@ -242,7 +281,7 @@ class WithL1DCacheSets(sets: Int) extends Config((site, here, up) => { }) class WithL1ICacheWays(ways: Int) extends Config((site, here, up) => { - case TilesLocated(InSubsystem) => up(TilesLocated(InSubsystem), site) map { + case TilesLocated(location) => up(TilesLocated(location), site) map { case tp: RocketTileAttachParams => tp.copy(tileParams = tp.tileParams.copy( icache = tp.tileParams.icache.map(_.copy(nWays = ways)))) case t => t @@ -250,7 +289,7 @@ class WithL1ICacheWays(ways: Int) extends Config((site, here, up) => { }) class WithL1DCacheWays(ways: Int) extends Config((site, here, up) => { - case TilesLocated(InSubsystem) => up(TilesLocated(InSubsystem), site) map { + case TilesLocated(location) => up(TilesLocated(location), site) map { case tp: RocketTileAttachParams => tp.copy(tileParams = tp.tileParams.copy( dcache = tp.tileParams.dcache.map(_.copy(nWays = ways)))) case t => t @@ -288,22 +327,22 @@ class WithBufferlessBroadcastHub extends Config((site, here, up) => { * DO NOT use this configuration. */ class WithIncoherentTiles extends Config((site, here, up) => { - case TilesLocated(InSubsystem) => up(TilesLocated(InSubsystem), site) map { + case TilesLocated(location) => up(TilesLocated(location), site) map { case tp: RocketTileAttachParams => tp.copy(crossingParams = tp.crossingParams.copy( master = tp.crossingParams.master match { - case x: TileMasterPortParams => x.copy(cork = Some(true)) + case x: HierarchicalElementMasterPortParams => x.copy(cork = Some(true)) case _ => throw new Exception("Unrecognized type for RocketCrossingParams.master") })) case t => t } - case BankedL2Key => up(BankedL2Key, site).copy( + case SubsystemBankedCoherenceKey => up(SubsystemBankedCoherenceKey, site).copy( coherenceManager = CoherenceManagerWrapper.incoherentManager ) }) class WithRV32 extends Config((site, here, up) => { case XLen => 32 - case TilesLocated(InSubsystem) => up(TilesLocated(InSubsystem), site) map { + case TilesLocated(location) => up(TilesLocated(location), site) map { case tp: RocketTileAttachParams => tp.copy(tileParams = tp.tileParams.copy( core = tp.tileParams.core.copy( fpu = tp.tileParams.core.fpu.map(_.copy(fLen = 32)), @@ -313,7 +352,7 @@ class WithRV32 extends Config((site, here, up) => { }) class WithFP16 extends Config((site, here, up) => { - case TilesLocated(InSubsystem) => up(TilesLocated(InSubsystem), site) map { + case TilesLocated(location) => up(TilesLocated(location), site) map { case tp: RocketTileAttachParams => tp.copy(tileParams = tp.tileParams.copy( core = tp.tileParams.core.copy( fpu = tp.tileParams.core.fpu.map(_.copy(minFLen = 16)) @@ -324,7 +363,7 @@ class WithFP16 extends Config((site, here, up) => { }) class WithNonblockingL1(nMSHRs: Int) extends Config((site, here, up) => { - case TilesLocated(InSubsystem) => up(TilesLocated(InSubsystem), site) map { + case TilesLocated(location) => up(TilesLocated(location), site) map { case tp: RocketTileAttachParams => tp.copy(tileParams = tp.tileParams.copy( dcache = tp.tileParams.dcache.map(_.copy(nMSHRs = nMSHRs)))) case t => t @@ -332,7 +371,7 @@ class WithNonblockingL1(nMSHRs: Int) extends Config((site, here, up) => { }) class WithNBreakpoints(hwbp: Int) extends Config ((site, here, up) => { - case TilesLocated(InSubsystem) => up(TilesLocated(InSubsystem), site) map { + case TilesLocated(location) => up(TilesLocated(location), site) map { case tp: RocketTileAttachParams => tp.copy(tileParams = tp.tileParams.copy( core = tp.tileParams.core.copy(nBreakpoints = hwbp))) case t => t @@ -340,7 +379,7 @@ class WithNBreakpoints(hwbp: Int) extends Config ((site, here, up) => { }) class WithHypervisor(hext: Boolean = true) extends Config((site, here, up) => { - case TilesLocated(InSubsystem) => up(TilesLocated(InSubsystem), site) map { + case TilesLocated(location) => up(TilesLocated(location), site) map { case tp: RocketTileAttachParams => tp.copy(tileParams = tp.tileParams.copy( core = tp.tileParams.core.copy(useHypervisor = hext))) case t => t @@ -368,7 +407,7 @@ class WithRoccExample extends Config((site, here, up) => { }) class WithDefaultBtb extends Config((site, here, up) => { - case TilesLocated(InSubsystem) => up(TilesLocated(InSubsystem), site) map { + case TilesLocated(location) => up(TilesLocated(location), site) map { case tp: RocketTileAttachParams => tp.copy(tileParams = tp.tileParams.copy( btb = Some(BTBParams()))) case t => t @@ -376,7 +415,7 @@ class WithDefaultBtb extends Config((site, here, up) => { }) class WithFastMulDiv extends Config((site, here, up) => { - case TilesLocated(InSubsystem) => up(TilesLocated(InSubsystem), site) map { + case TilesLocated(location) => up(TilesLocated(location), site) map { case tp: RocketTileAttachParams => tp.copy(tileParams = tp.tileParams.copy( core = tp.tileParams.core.copy(mulDiv = Some( MulDivParams(mulUnroll = 8, mulEarlyOut = (site(XLen) > 32), divEarlyOut = true))))) @@ -385,7 +424,7 @@ class WithFastMulDiv extends Config((site, here, up) => { }) class WithoutMulDiv extends Config((site, here, up) => { - case TilesLocated(InSubsystem) => up(TilesLocated(InSubsystem), site) map { + case TilesLocated(location) => up(TilesLocated(location), site) map { case tp: RocketTileAttachParams => tp.copy(tileParams = tp.tileParams.copy( core = tp.tileParams.core.copy(mulDiv = None))) case t => t @@ -393,7 +432,7 @@ class WithoutMulDiv extends Config((site, here, up) => { }) class WithoutFPU extends Config((site, here, up) => { - case TilesLocated(InSubsystem) => up(TilesLocated(InSubsystem), site) map { + case TilesLocated(location) => up(TilesLocated(location), site) map { case tp: RocketTileAttachParams => tp.copy(tileParams = tp.tileParams.copy( core = tp.tileParams.core.copy(fpu = None))) case t => t @@ -401,7 +440,7 @@ class WithoutFPU extends Config((site, here, up) => { }) class WithFPUWithoutDivSqrt extends Config((site, here, up) => { - case TilesLocated(InSubsystem) => up(TilesLocated(InSubsystem), site) map { + case TilesLocated(location) => up(TilesLocated(location), site) map { case tp: RocketTileAttachParams => tp.copy(tileParams = tp.tileParams.copy( core = tp.tileParams.core.copy(fpu = tp.tileParams.core.fpu.map(_.copy(divSqrt = false))))) case t => t @@ -441,7 +480,7 @@ class WithClockGateModel(file: String = "/vsrc/EICG_wrapper.v") extends Config(( }) class WithSynchronousRocketTiles extends Config((site, here, up) => { - case TilesLocated(InSubsystem) => up(TilesLocated(InSubsystem), site) map { + case TilesLocated(location) => up(TilesLocated(location), site) map { case tp: RocketTileAttachParams => tp.copy(crossingParams = tp.crossingParams.copy( crossingType = SynchronousCrossing())) case t => t @@ -449,7 +488,7 @@ class WithSynchronousRocketTiles extends Config((site, here, up) => { }) class WithAsynchronousRocketTiles(depth: Int, sync: Int) extends Config((site, here, up) => { - case TilesLocated(InSubsystem) => up(TilesLocated(InSubsystem), site) map { + case TilesLocated(location) => up(TilesLocated(location), site) map { case tp: RocketTileAttachParams => tp.copy(crossingParams = tp.crossingParams.copy( crossingType = AsynchronousCrossing())) case t => t @@ -457,7 +496,7 @@ class WithAsynchronousRocketTiles(depth: Int, sync: Int) extends Config((site, h }) class WithRationalRocketTiles extends Config((site, here, up) => { - case TilesLocated(InSubsystem) => up(TilesLocated(InSubsystem), site) map { + case TilesLocated(location) => up(TilesLocated(location), site) map { case tp: RocketTileAttachParams => tp.copy(crossingParams = tp.crossingParams.copy( crossingType = RationalCrossing())) case t => t @@ -467,7 +506,6 @@ class WithRationalRocketTiles extends Config((site, here, up) => { class WithEdgeDataBits(dataBits: Int) extends Config((site, here, up) => { case MemoryBusKey => up(MemoryBusKey, site).copy(beatBytes = dataBits/8) case ExtIn => up(ExtIn, site).map(_.copy(beatBytes = dataBits/8)) - }) class WithJtagDTM extends Config ((site, here, up) => { @@ -560,7 +598,7 @@ class WithScratchpadsBaseAddress(address: BigInt) extends Config((site, here, up }) class WithScratchpadsOnly extends Config((site, here, up) => { - case TilesLocated(InSubsystem) => up(TilesLocated(InSubsystem), site) map { + case TilesLocated(location) => up(TilesLocated(location), site) map { case tp: RocketTileAttachParams => tp.copy(tileParams = tp.tileParams.copy( core = tp.tileParams.core.copy(useVM = false), dcache = tp.tileParams.dcache.map(_.copy( @@ -619,16 +657,41 @@ class WithDontDriveBusClocksFromSBus extends Config((site, here, up) => { case DriveClocksFromSBus => false }) -class WithCloneRocketTiles(n: Int = 1, cloneHart: Int = 0, overrideIdOffset: Option[Int] = None) extends Config((site, here, up) => { - case TilesLocated(InSubsystem) => { - val prev = up(TilesLocated(InSubsystem), site) - val idOffset = overrideIdOffset.getOrElse(prev.size) - val tileAttachParams = prev(cloneHart).asInstanceOf[RocketTileAttachParams] +class WithCloneRocketTiles( + n: Int = 1, + cloneTileId: Int = 0, + location: HierarchicalLocation = InSubsystem, + cloneLocation: HierarchicalLocation = InSubsystem +) extends Config((site, here, up) => { + case TilesLocated(`location`) => { + val prev = up(TilesLocated(location), site) + val idOffset = up(NumTiles) + val tileAttachParams = up(TilesLocated(cloneLocation)).find(_.tileParams.tileId == cloneTileId) + .get.asInstanceOf[RocketTileAttachParams] (0 until n).map { i => - CloneTileAttachParams(cloneHart, tileAttachParams.copy( - tileParams = tileAttachParams.tileParams.copy(hartId = i + idOffset) + CloneTileAttachParams(cloneTileId, tileAttachParams.copy( + tileParams = tileAttachParams.tileParams.copy(tileId = i + idOffset) )) } ++ prev } + case NumTiles => up(NumTiles) + n }) +class WithCloneCluster( + clusterId: Int, + cloneClusterId: Int = 0, + location: HierarchicalLocation = InSubsystem, + cloneLocation: HierarchicalLocation = InSubsystem +) extends Config((site, here, up) => { + case ClustersLocated(`location`) => { + val prev = up(ClustersLocated(location)) + val clusterAttachParams = up(ClustersLocated(cloneLocation)).find(_.clusterParams.clusterId == cloneClusterId) + .get.asInstanceOf[ClusterAttachParams] + prev :+ CloneClusterAttachParams( + cloneClusterId, + clusterAttachParams.copy(clusterParams = clusterAttachParams.clusterParams.copy(clusterId = clusterId)) + ) + } + case TLNetworkTopologyLocated(InCluster(`clusterId`)) => site(TLNetworkTopologyLocated(InCluster(cloneClusterId))) + case PossibleTileLocations => up(PossibleTileLocations) :+ InCluster(clusterId) +}) diff --git a/src/main/scala/subsystem/HasHierarchicalElements.scala b/src/main/scala/subsystem/HasHierarchicalElements.scala new file mode 100644 index 00000000000..63f2ff14f18 --- /dev/null +++ b/src/main/scala/subsystem/HasHierarchicalElements.scala @@ -0,0 +1,234 @@ +// See LICENSE.SiFive for license details. + +package freechips.rocketchip.subsystem + +import chisel3._ +import chisel3.dontTouch +import org.chipsalliance.cde.config.{Field, Parameters} +import freechips.rocketchip.devices.debug.{TLDebugModule, HasPeripheryDebug} +import freechips.rocketchip.devices.tilelink._ +import freechips.rocketchip.diplomacy._ +import freechips.rocketchip.interrupts._ +import freechips.rocketchip.tile._ +import freechips.rocketchip.tilelink._ +import freechips.rocketchip.prci.{ClockGroup, ResetCrossingType, ClockGroupNode, ClockDomain} +import freechips.rocketchip.util._ +import freechips.rocketchip.rocket.{TracedInstruction} +import scala.collection.immutable.SortedMap + +/** A default implementation of parameterizing the connectivity of the port where the tile is the master. + * Optional timing buffers and/or an optional CacheCork can be inserted in the interconnect's clock domain. + */ +case class HierarchicalElementMasterPortParams( + buffers: Int = 0, + cork: Option[Boolean] = None, + where: TLBusWrapperLocation = SBUS +) extends HierarchicalElementPortParamsLike { + def injectNode(context: Attachable)(implicit p: Parameters): TLNode = { + (TLBuffer.chainNode(buffers) :=* cork.map { u => TLCacheCork(unsafe = u) } .getOrElse { TLTempNode() }) + } +} + +object HierarchicalElementMasterPortParams { + def locationDefault(loc: HierarchicalLocation) = loc match { + case InSubsystem => HierarchicalElementMasterPortParams() + case InCluster(clusterId) => HierarchicalElementMasterPortParams(where=CSBUS(clusterId)) + } +} + +/** A default implementation of parameterizing the connectivity of the port giving access to slaves inside the tile. + * Optional timing buffers and/or an optional BusBlocker adapter can be inserted in the interconnect's clock domain. + */ +case class HierarchicalElementSlavePortParams( + buffers: Int = 0, + blockerCtrlAddr: Option[BigInt] = None, + blockerCtrlWhere: TLBusWrapperLocation = CBUS, + where: TLBusWrapperLocation = CBUS +) extends HierarchicalElementPortParamsLike { + def injectNode(context: Attachable)(implicit p: Parameters): TLNode = { + val controlBus = context.locateTLBusWrapper(where) + val blockerBus = context.locateTLBusWrapper(blockerCtrlWhere) + blockerCtrlAddr + .map { BasicBusBlockerParams(_, blockerBus.beatBytes, controlBus.beatBytes) } + .map { bbbp => + val blocker = LazyModule(new BasicBusBlocker(bbbp)) + blockerBus.coupleTo("tile_slave_port_bus_blocker") { blocker.controlNode := TLFragmenter(blockerBus) := _ } + blocker.node :*= TLBuffer.chainNode(buffers) + } .getOrElse { TLBuffer.chainNode(buffers) } + } +} + +object HierarchicalElementSlavePortParams { + def locationDefault(loc: HierarchicalLocation) = loc match { + case InSubsystem => HierarchicalElementSlavePortParams() + case InCluster(clusterId) => HierarchicalElementSlavePortParams(where=CCBUS(clusterId), blockerCtrlWhere=CCBUS(clusterId)) + } +} + +/** InstantiatesTiles adds a Config-urable sequence of HierarchicalElements of any type + * to the subsystem class into which it is mixed. + */ +trait InstantiatesHierarchicalElements { this: LazyModule with Attachable => + val location: HierarchicalLocation + + /** Record the order in which to instantiate all tiles, based on statically-assigned ids. + * + * Note that these ids, which are often used as the tiles' default hartid input, + * may or may not be those actually reflected at runtime in e.g. the $mhartid CSR + */ + val tileAttachParams: Seq[CanAttachTile] = p(TilesLocated(location)).sortBy(_.tileParams.tileId) + val tileParams: Seq[TileParams] = tileAttachParams.map(_.tileParams) + val tileCrossingTypes: Seq[ClockCrossingType] = tileAttachParams.map(_.crossingParams.crossingType) + + /** The actual list of instantiated tiles in this block. */ + val tile_prci_domains: SortedMap[Int, TilePRCIDomain[_]] = tileAttachParams.foldLeft(SortedMap[Int, TilePRCIDomain[_]]()) { + case (instantiated, params) => instantiated + (params.tileParams.tileId -> params.instantiate(tileParams, instantiated)(p)) + } + + val clusterAttachParams: Seq[CanAttachCluster] = p(ClustersLocated(location)).sortBy(_.clusterParams.clusterId) + val clusterParams: Seq[ClusterParams] = clusterAttachParams.map(_.clusterParams) + val clusterCrossingTypes: Seq[ClockCrossingType] = clusterAttachParams.map(_.crossingParams.crossingType) + val cluster_prci_domains: SortedMap[Int, ClusterPRCIDomain] = clusterAttachParams.foldLeft(SortedMap[Int, ClusterPRCIDomain]()) { + case (instantiated, params) => instantiated + (params.clusterParams.clusterId -> params.instantiate(clusterParams, instantiated)(p)) + } + + val element_prci_domains: Seq[HierarchicalElementPRCIDomain[_]] = tile_prci_domains.values.toSeq ++ cluster_prci_domains.values.toSeq + + val leafTiles: SortedMap[Int, BaseTile] = SortedMap(tile_prci_domains.mapValues(_.element.asInstanceOf[BaseTile]).toSeq.sortBy(_._1):_*) + val totalTiles: SortedMap[Int, BaseTile] = (leafTiles ++ cluster_prci_domains.values.map(_.element.totalTiles).flatten) + + // Helper functions for accessing certain parameters that are popular to refer to in subsystem code + def nLeafTiles: Int = leafTiles.size + def nTotalTiles: Int = totalTiles.size + def leafTileIdList: Seq[Int] = leafTiles.keys.toSeq.sorted + def totalTileIdList: Seq[Int] = totalTiles.keys.toSeq.sorted + def localIntCounts: SortedMap[Int, Int] = totalTiles.mapValues(_.tileParams.core.nLocalInterrupts).to(SortedMap) + + require(totalTileIdList.distinct.size == totalTiles.size, s"Every tile must be statically assigned a unique id, but got:\n${totalTileIdList}") +} + +/** HasTiles instantiates and also connects a Config-urable sequence of tiles of any type to subsystem interconnect resources. */ +trait HasHierarchicalElements extends DefaultHierarchicalElementContextType +{ this: LazyModule with Attachable with InstantiatesHierarchicalElements => + implicit val p: Parameters + + // connect all the tiles to interconnect attachment points made available in this subsystem context + tileAttachParams.foreach { params => + params.connect(tile_prci_domains(params.tileParams.tileId).asInstanceOf[TilePRCIDomain[params.TileType]], this.asInstanceOf[params.TileContextType]) + } + clusterAttachParams.foreach { params => + params.connect(cluster_prci_domains(params.clusterParams.clusterId).asInstanceOf[ClusterPRCIDomain], this.asInstanceOf[params.ClusterContextType]) + } +} + +/** Provides some Chisel connectivity to certain tile IOs + * This trait is intended for the root subsystem + */ +trait HasHierarchicalElementsRootContextModuleImp extends LazyRawModuleImp { + val outer: InstantiatesHierarchicalElements with HasHierarchicalElements with HasHierarchicalElementsRootContext with HasTileInputConstants + + val reset_vector = outer.tileResetVectorIONodes.zipWithIndex.map { case (n, i) => n.makeIO(s"reset_vector_$i") } + val tile_hartids = outer.tileHartIdIONodes.zipWithIndex.map { case (n, i) => n.makeIO(s"tile_hartids_$i") } + + val meip = if (outer.meipIONode.isDefined) Some(IO(Input(Vec(outer.meipIONode.get.out.size, Bool())))) else None + meip.foreach { m => + m.zipWithIndex.foreach{ case (pin, i) => + (outer.meipIONode.get.out(i)._1)(0) := pin + } + } + val seip = if (outer.seipIONode.isDefined) Some(IO(Input(Vec(outer.seipIONode.get.out.size, Bool())))) else None + seip.foreach { s => + s.zipWithIndex.foreach{ case (pin, i) => + (outer.seipIONode.get.out(i)._1)(0) := pin + } + } + val nmi = outer.nmiIONodes.map { case (i, node) => + node.makeIO(s"nmi_$i") + } +} + +/** Most tile types require only these traits in order for their standardized connect functions to apply. + * + * BaseTiles subtypes with different needs can extend this trait to provide themselves with + * additional external connection points. + */ +trait DefaultHierarchicalElementContextType + extends Attachable + with HasTileNotificationSinks +{ this: LazyModule with Attachable => + def msipDomain: LazyScope + val msipNodes: SortedMap[Int, IntNode] + def meipDomain: LazyScope + val meipNodes: SortedMap[Int, IntNode] + def seipDomain: LazyScope + val seipNodes: SortedMap[Int, IntNode] + val tileToPlicNodes: SortedMap[Int, IntNode] + val debugNodes: SortedMap[Int, IntSyncNode] + val nmiNodes: SortedMap[Int, BundleBridgeNode[NMI]] + val tileHartIdNodes: SortedMap[Int, BundleBridgeNode[UInt]] + val tileResetVectorNodes: SortedMap[Int, BundleBridgeNode[UInt]] + val traceCoreNodes: SortedMap[Int, BundleBridgeNode[TraceCoreInterface]] + val traceNodes: SortedMap[Int, BundleBridgeNode[TraceBundle]] +} + +/** This trait provides the tile attachment context for the root (outermost) subsystem */ +trait HasHierarchicalElementsRootContext +{ this: HasHierarchicalElements + with HasTileNotificationSinks + with InstantiatesHierarchicalElements => + + val clintOpt: Option[CLINT] + val clintDomainOpt: Option[ClockDomain] + val plicOpt: Option[TLPLIC] + val plicDomainOpt: Option[ClockDomain] + val debugOpt: Option[TLDebugModule] + + def msipDomain = clintDomainOpt.getOrElse(this) + def meipDomain = plicDomainOpt.getOrElse(this) + def seipDomain = plicDomainOpt.getOrElse(this) + + val msipNodes: SortedMap[Int, IntNode] = (0 until nTotalTiles).map { i => + (i, IntEphemeralNode()) + }.to(SortedMap) + msipNodes.foreach { + _._2 := clintOpt.map(_.intnode).getOrElse(NullIntSource(sources = CLINTConsts.ints)) + } + + val meipIONode = Option.when(plicOpt.isEmpty)(IntNexusNode( + sourceFn = { _ => IntSourcePortParameters(Seq(IntSourceParameters(1))) }, + sinkFn = { _ => IntSinkPortParameters(Seq(IntSinkParameters())) }, + outputRequiresInput = false, + inputRequiresOutput = false)) + val meipNodes: SortedMap[Int, IntNode] = (0 until nTotalTiles).map { i => + (i, IntEphemeralNode() := plicOpt.map(_.intnode).getOrElse(meipIONode.get)) + }.to(SortedMap) + + val seipIONode = Option.when(plicOpt.isEmpty)(IntNexusNode( + sourceFn = { _ => IntSourcePortParameters(Seq(IntSourceParameters(1))) }, + sinkFn = { _ => IntSinkPortParameters(Seq(IntSinkParameters())) }, + outputRequiresInput = false, + inputRequiresOutput = false)) + val seipNodes: SortedMap[Int, IntNode] = totalTiles.filter { case (_, t) => t.tileParams.core.hasSupervisorMode } + .mapValues( _ => IntEphemeralNode() := plicOpt.map(_.intnode).getOrElse(seipIONode.get)).to(SortedMap) + + val tileToPlicNodes: SortedMap[Int, IntNode] = (0 until nTotalTiles).map { i => + plicOpt.map(o => (i, o.intnode :=* IntEphemeralNode())) + }.flatten.to(SortedMap) + + val debugNodes: SortedMap[Int, IntSyncNode] = (0 until nTotalTiles).map { i => + (i, IntSyncIdentityNode()) + }.to(SortedMap) + + debugNodes.foreach { case (hartid, node) => + node := debugOpt.map(_.intnode).getOrElse(NullIntSyncSource()) + } + + val nmiHarts = totalTiles.filter { case (_, t) => t.tileParams.core.useNMI }.keys + val nmiIONodes = nmiHarts.map { i => (i, BundleBridgeSource[NMI]()) }.to(SortedMap) + val nmiNodes: SortedMap[Int, BundleBridgeNode[NMI]] = nmiIONodes.map { case (i, n) => + (i, BundleBridgeEphemeralNode[NMI]() := n) + }.to(SortedMap) + + val traceCoreNodes: SortedMap[Int, BundleBridgeSink[TraceCoreInterface]] = (0 until nTotalTiles).map { i => (i, BundleBridgeSink[TraceCoreInterface]()) }.to(SortedMap) + val traceNodes: SortedMap[Int, BundleBridgeSink[TraceBundle]] = (0 until nTotalTiles).map { i => (i, BundleBridgeSink[TraceBundle]()) }.to(SortedMap) +} diff --git a/src/main/scala/subsystem/HasTiles.scala b/src/main/scala/subsystem/HasTiles.scala index 5c65ed4cd81..ff06ccff4a6 100644 --- a/src/main/scala/subsystem/HasTiles.scala +++ b/src/main/scala/subsystem/HasTiles.scala @@ -5,17 +5,26 @@ package freechips.rocketchip.subsystem import chisel3._ import chisel3.dontTouch import org.chipsalliance.cde.config.{Field, Parameters} -import freechips.rocketchip.devices.tilelink.{BasicBusBlocker, BasicBusBlockerParams, CLINTConsts, PLICKey, CanHavePeripheryPLIC, CanHavePeripheryCLINT} +import freechips.rocketchip.devices.tilelink._ +import freechips.rocketchip.devices.debug.{TLDebugModule} import freechips.rocketchip.diplomacy._ import freechips.rocketchip.interrupts._ import freechips.rocketchip.tile._ import freechips.rocketchip.tilelink._ -import freechips.rocketchip.prci.{ClockGroup, ResetCrossingType, ClockGroupNode} +import freechips.rocketchip.prci._ import freechips.rocketchip.util._ +import freechips.rocketchip.rocket.{TracedInstruction} +import scala.collection.immutable.SortedMap /** Entry point for Config-uring the presence of Tiles */ case class TilesLocated(loc: HierarchicalLocation) extends Field[Seq[CanAttachTile]](Nil) +/** List of HierarchicalLocations which might contain a Tile */ +case object PossibleTileLocations extends Field[Seq[HierarchicalLocation]](Nil) + +/** For determining static tile id */ +case object NumTiles extends Field[Int](0) + /** Whether to add timing-closure registers along the path of the hart id * as it propagates through the subsystem and into the tile. * @@ -24,112 +33,17 @@ case class TilesLocated(loc: HierarchicalLocation) extends Field[Seq[CanAttachTi */ case object InsertTimingClosureRegistersOnHartIds extends Field[Boolean](false) -/** Whether per-tile hart ids are going to be driven as inputs into the subsystem, +/** Whether per-tile hart ids are going to be driven as inputs into a HasTiles block, * and if so, what their width should be. */ -case object SubsystemExternalHartIdWidthKey extends Field[Option[Int]](None) +case object HasTilesExternalHartIdWidthKey extends Field[Option[Int]](None) -/** Whether per-tile reset vectors are going to be driven as inputs into the subsystem. +/** Whether per-tile reset vectors are going to be driven as inputs into a HasTiles block. * * Unlike the hart ids, the reset vector width is determined by the sinks within the tiles, * based on the size of the address map visible to the tiles. */ -case object SubsystemExternalResetVectorKey extends Field[Boolean](true) - -/** An interface for describing the parameteization of how Tiles are connected to interconnects */ -trait TileCrossingParamsLike { - /** The type of clock crossing that should be inserted at the tile boundary. */ - def crossingType: ClockCrossingType - /** Parameters describing the contents and behavior of the point where the tile is attached as an interconnect master. */ - def master: TilePortParamsLike - /** Parameters describing the contents and behavior of the point where the tile is attached as an interconnect slave. */ - def slave: TilePortParamsLike - /** The subnetwork location of the device selecting the apparent base address of MMIO devices inside the tile */ - def mmioBaseAddressPrefixWhere: TLBusWrapperLocation - /** Inject a reset management subgraph that effects the tile child reset only */ - def resetCrossingType: ResetCrossingType - /** Keep the tile clock separate from the interconnect clock (e.g. even if they are synchronous to one another) */ - def forceSeparateClockReset: Boolean -} - -/** An interface for describing the parameterization of how a particular tile port is connected to an interconnect */ -trait TilePortParamsLike { - /** The subnetwork location of the interconnect to which this tile port should be connected. */ - def where: TLBusWrapperLocation - /** Allows port-specific adapters to be injected into the interconnect side of the attachment point. */ - def injectNode(context: Attachable)(implicit p: Parameters): TLNode -} - -/** A default implementation of parameterizing the connectivity of the port where the tile is the master. - * Optional timing buffers and/or an optional CacheCork can be inserted in the interconnect's clock domain. - */ -case class TileMasterPortParams( - buffers: Int = 0, - cork: Option[Boolean] = None, - where: TLBusWrapperLocation = SBUS -) extends TilePortParamsLike { - def injectNode(context: Attachable)(implicit p: Parameters): TLNode = { - (TLBuffer.chainNode(buffers) :=* cork.map { u => TLCacheCork(unsafe = u) } .getOrElse { TLTempNode() }) - } -} - -/** A default implementation of parameterizing the connectivity of the port giving access to slaves inside the tile. - * Optional timing buffers and/or an optional BusBlocker adapter can be inserted in the interconnect's clock domain. - */ -case class TileSlavePortParams( - buffers: Int = 0, - blockerCtrlAddr: Option[BigInt] = None, - blockerCtrlWhere: TLBusWrapperLocation = CBUS, - where: TLBusWrapperLocation = CBUS -) extends TilePortParamsLike { - def injectNode(context: Attachable)(implicit p: Parameters): TLNode = { - val controlBus = context.locateTLBusWrapper(where) - val blockerBus = context.locateTLBusWrapper(blockerCtrlWhere) - blockerCtrlAddr - .map { BasicBusBlockerParams(_, blockerBus.beatBytes, controlBus.beatBytes) } - .map { bbbp => - val blocker = LazyModule(new BasicBusBlocker(bbbp)) - blockerBus.coupleTo("tile_slave_port_bus_blocker") { blocker.controlNode := TLFragmenter(blockerBus) := _ } - blocker.node :*= TLBuffer.chainNode(buffers) - } .getOrElse { TLBuffer.chainNode(buffers) } - } -} - -/** These are sources of interrupts that are driven into the tile. - * They need to be instantiated before tiles are attached to the subsystem containing them. - */ -trait HasTileInterruptSources - extends CanHavePeripheryPLIC - with CanHavePeripheryCLINT - with InstantiatesTiles -{ this: BaseSubsystem => // TODO ideally this bound would be softened to LazyModule - /** meipNode is used to create a single bit subsystem input in Configs without a PLIC */ - val meipNode = p(PLICKey) match { - case Some(_) => None - case None => Some(IntNexusNode( - sourceFn = { _ => IntSourcePortParameters(Seq(IntSourceParameters(1))) }, - sinkFn = { _ => IntSinkPortParameters(Seq(IntSinkParameters())) }, - outputRequiresInput = false, - inputRequiresOutput = false)) - } - val seipNode = p(PLICKey) match { - case Some(_) => None - case None => Some(IntNexusNode( - sourceFn = { _ => IntSourcePortParameters(Seq(IntSourceParameters(1))) }, - sinkFn = { _ => IntSinkPortParameters(Seq(IntSinkParameters())) }, - outputRequiresInput = false, - inputRequiresOutput = false)) - } - /** Source of Non-maskable Interrupt (NMI) input bundle to each tile. */ - val tileNMINode = BundleBridgeEphemeralNode[NMI]() - val tileNMIIONodes: Seq[BundleBridgeSource[NMI]] = { - Seq.fill(tiles.size) { - val nmiSource = BundleBridgeSource[NMI]() - tileNMINode := nmiSource - nmiSource - } - } -} +case object HasTilesExternalResetVectorKey extends Field[Boolean](true) /** These are sources of "constants" that are driven into the tile. * @@ -137,9 +51,11 @@ trait HasTileInterruptSources * they may be either tied to a contant value or programmed during boot or reset. * They need to be instantiated before tiles are attached within the subsystem containing them. */ -trait HasTileInputConstants extends InstantiatesTiles { this: BaseSubsystem => +trait HasTileInputConstants { this: LazyModule with Attachable with InstantiatesHierarchicalElements => /** tileHartIdNode is used to collect publishers and subscribers of hartids. */ - val tileHartIdNode = BundleBridgeEphemeralNode[UInt]() + val tileHartIdNodes: SortedMap[Int, BundleBridgeEphemeralNode[UInt]] = (0 until nTotalTiles).map { i => + (i, BundleBridgeEphemeralNode[UInt]()) + }.to(SortedMap) /** tileHartIdNexusNode is a BundleBridgeNexus that collects dynamic hart prefixes. * @@ -156,7 +72,7 @@ trait HasTileInputConstants extends InstantiatesTiles { this: BaseSubsystem => val tileHartIdNexusNode = LazyModule(new BundleBridgeNexus[UInt]( inputFn = BundleBridgeNexus.orReduction[UInt](registered = p(InsertTimingClosureRegistersOnHartIds)) _, outputFn = (prefix: UInt, n: Int) => Seq.tabulate(n) { i => - val y = dontTouch(prefix | hartIdList(i).U(p(MaxHartIdBits).W)) // dontTouch to keep constant prop from breaking tile dedup + val y = dontTouch(prefix | totalTileIdList(i).U(p(MaxHartIdBits).W)) // dontTouch to keep constant prop from breaking tile dedup if (p(InsertTimingClosureRegistersOnHartIds)) BundleBridgeNexus.safeRegNext(y) else y }, default = Some(() => 0.U(p(MaxHartIdBits).W)), @@ -166,7 +82,9 @@ trait HasTileInputConstants extends InstantiatesTiles { this: BaseSubsystem => // TODO: Replace the DebugModuleHartSelFuncs config key with logic to consume the dynamic hart IDs /** tileResetVectorNode is used to collect publishers and subscribers of tile reset vector addresses. */ - val tileResetVectorNode = BundleBridgeEphemeralNode[UInt]() + val tileResetVectorNodes: SortedMap[Int, BundleBridgeEphemeralNode[UInt]] = (0 until nTotalTiles).map { i => + (i, BundleBridgeEphemeralNode[UInt]()) + }.to(SortedMap) /** tileResetVectorNexusNode is a BundleBridgeNexus that accepts a single reset vector source, and broadcasts it to all tiles. */ val tileResetVectorNexusNode = BundleBroadcast[UInt]( @@ -177,26 +95,32 @@ trait HasTileInputConstants extends InstantiatesTiles { this: BaseSubsystem => * * Or, if such IOs are not configured to exist, tileHartIdNexusNode is used to supply an id to each tile. */ - val tileHartIdIONodes: Seq[BundleBridgeSource[UInt]] = p(SubsystemExternalHartIdWidthKey) match { - case Some(w) => Seq.fill(tiles.size) { + val tileHartIdIONodes: Seq[BundleBridgeSource[UInt]] = p(HasTilesExternalHartIdWidthKey) match { + case Some(w) => (0 until nTotalTiles).map { i => val hartIdSource = BundleBridgeSource(() => UInt(w.W)) - tileHartIdNode := hartIdSource + tileHartIdNodes(i) := hartIdSource hartIdSource } - case None => { tileHartIdNode :*= tileHartIdNexusNode; Nil } + case None => { + (0 until nTotalTiles).map { i => tileHartIdNodes(i) :*= tileHartIdNexusNode } + Nil + } } /** tileResetVectorIONodes may generate subsystem IOs, one per tile, allowing the parent to assign unique reset vectors. * * Or, if such IOs are not configured to exist, tileResetVectorNexusNode is used to supply a single reset vector to every tile. */ - val tileResetVectorIONodes: Seq[BundleBridgeSource[UInt]] = p(SubsystemExternalResetVectorKey) match { - case true => Seq.fill(tiles.size) { + val tileResetVectorIONodes: Seq[BundleBridgeSource[UInt]] = p(HasTilesExternalResetVectorKey) match { + case true => (0 until nTotalTiles).map { i => val resetVectorSource = BundleBridgeSource[UInt]() - tileResetVectorNode := resetVectorSource + tileResetVectorNodes(i) := resetVectorSource resetVectorSource } - case false => { tileResetVectorNode :*= tileResetVectorNexusNode; Nil } + case false => { + (0 until nTotalTiles).map { i => tileResetVectorNodes(i) :*= tileResetVectorNexusNode } + Nil + } } } @@ -218,20 +142,6 @@ trait HasTileNotificationSinks { this: LazyModule => tileCeaseSinkNode := tileCeaseXbarNode } -/** Most tile types require only these traits in order for their standardized connect functions to apply. - * - * BaseTiles subtypes with different needs can extend this trait to provide themselves with - * additional external connection points. - */ -trait DefaultTileContextType - extends Attachable - with HasTileInterruptSources - with HasTileNotificationSinks - with HasTileInputConstants -{ this: BaseSubsystem => - val debugNode: IntSyncOutwardNode -} // TODO: ideally this bound would be softened to LazyModule - /** Standardized interface by which parameterized tiles can be attached to contexts containing interconnect resources. * * Sub-classes of this trait can optionally override the individual connect functions in order to specialize @@ -240,15 +150,15 @@ trait DefaultTileContextType */ trait CanAttachTile { type TileType <: BaseTile - type TileContextType <: DefaultTileContextType + type TileContextType <: DefaultHierarchicalElementContextType def tileParams: InstantiableTileParams[TileType] - def crossingParams: TileCrossingParamsLike + def crossingParams: HierarchicalElementCrossingParamsLike /** Narrow waist through which all tiles are intended to pass while being instantiated. */ - def instantiate(allTileParams: Seq[TileParams], instantiatedTiles: Seq[TilePRCIDomain[_]])(implicit p: Parameters): TilePRCIDomain[TileType] = { - val clockSinkParams = tileParams.clockSinkParams.copy(name = Some(s"${tileParams.name.getOrElse("core")}_${tileParams.hartId}")) + def instantiate(allTileParams: Seq[TileParams], instantiatedTiles: SortedMap[Int, TilePRCIDomain[_]])(implicit p: Parameters): TilePRCIDomain[TileType] = { + val clockSinkParams = tileParams.clockSinkParams.copy(name = Some(tileParams.uniqueName)) val tile_prci_domain = LazyModule(new TilePRCIDomain[TileType](clockSinkParams, crossingParams) { self => - val tile = self.tile_reset_domain { LazyModule(tileParams.instantiate(crossingParams, PriorityMuxHartIdFromSeq(allTileParams))) } + val element = self.element_reset_domain { LazyModule(tileParams.instantiate(crossingParams, PriorityMuxHartIdFromSeq(allTileParams))) } }) tile_prci_domain } @@ -261,13 +171,14 @@ trait CanAttachTile { connectPRC(domain, context) connectOutputNotifications(domain, context) connectInputConstants(domain, context) + connectTrace(domain, context) } /** Connect the port where the tile is the master to a TileLink interconnect. */ def connectMasterPorts(domain: TilePRCIDomain[TileType], context: Attachable): Unit = { implicit val p = context.p val dataBus = context.locateTLBusWrapper(crossingParams.master.where) - dataBus.coupleFrom(tileParams.name.getOrElse("tile")) { bus => + dataBus.coupleFrom(tileParams.baseName) { bus => bus :=* crossingParams.master.injectNode(context) :=* domain.crossMasterPort(crossingParams.crossingType) } } @@ -277,7 +188,7 @@ trait CanAttachTile { implicit val p = context.p DisableMonitors { implicit p => val controlBus = context.locateTLBusWrapper(crossingParams.slave.where) - controlBus.coupleTo(tileParams.name.getOrElse("tile")) { bus => + controlBus.coupleTo(tileParams.baseName) { bus => domain.crossSlavePort(crossingParams.crossingType) :*= crossingParams.slave.injectNode(context) :*= TLWidthWidget(controlBus.beatBytes) :*= bus } } @@ -291,61 +202,66 @@ trait CanAttachTile { // we stub out missing interrupts with constant sources here. // 1. Debug interrupt is definitely asynchronous in all cases. - domain.tile.intInwardNode := domain { IntSyncAsyncCrossingSink(3) } := context.debugNode + domain.element.intInwardNode := domain { IntSyncAsyncCrossingSink(3) } := + context.debugNodes(domain.element.tileId) - // 2. The CLINT and PLIC output interrupts are synchronous to the TileLink bus clock, + // 2. The CLINT and PLIC output interrupts are synchronous to the CLINT/PLIC respectively, // so might need to be synchronized depending on the Tile's crossing type. // From CLINT: "msip" and "mtip" - domain.crossIntIn(crossingParams.crossingType) := - context.clintOpt.map { _.intnode } - .getOrElse { NullIntSource(sources = CLINTConsts.ints) } + context.msipDomain { + domain.crossIntIn(crossingParams.crossingType, domain.element.intInwardNode) := + context.msipNodes(domain.element.tileId) + } // From PLIC: "meip" - domain.crossIntIn(crossingParams.crossingType) := - context.plicOpt .map { _.intnode } - .getOrElse { context.meipNode.get } + context.meipDomain { + domain.crossIntIn(crossingParams.crossingType, domain.element.intInwardNode) := + context.meipNodes(domain.element.tileId) + } // From PLIC: "seip" (only if supervisor mode is enabled) - if (domain.tile.tileParams.core.hasSupervisorMode) { - domain.crossIntIn(crossingParams.crossingType) := - context.plicOpt .map { _.intnode } - .getOrElse { context.seipNode.get } + if (domain.element.tileParams.core.hasSupervisorMode) { + context.seipDomain { + domain.crossIntIn(crossingParams.crossingType, domain.element.intInwardNode) := + context.seipNodes(domain.element.tileId) + } } // 3. Local Interrupts ("lip") are required to already be synchronous to the Tile's clock. - // (they are connected to domain.tile.intInwardNode in a seperate trait) + // (they are connected to domain.element.intInwardNode in a seperate trait) // 4. Interrupts coming out of the tile are sent to the PLIC, // so might need to be synchronized depending on the Tile's crossing type. - context.plicOpt.foreach { plic => - FlipRendering { implicit p => - plic.intnode :=* domain.crossIntOut(crossingParams.crossingType, domain.tile.intOutwardNode) - } + context.tileToPlicNodes.get(domain.element.tileId).foreach { node => + FlipRendering { implicit p => domain.element.intOutwardNode.foreach { out => + node :*= domain.crossIntOut(crossingParams.crossingType, out) + }} } // 5. Connect NMI inputs to the tile. These inputs are synchronous to the respective core_clock. - domain.tile.nmiNode := context.tileNMINode + domain.element.nmiNode.foreach(_ := context.nmiNodes(domain.element.tileId)) } /** Notifications of tile status are connected to be broadcast without needing to be clock-crossed. */ def connectOutputNotifications(domain: TilePRCIDomain[TileType], context: TileContextType): Unit = { implicit val p = context.p - context.tileHaltXbarNode :=* domain.crossIntOut(NoCrossing, domain.tile.haltNode) - context.tileWFIXbarNode :=* domain.crossIntOut(NoCrossing, domain.tile.wfiNode) - context.tileCeaseXbarNode :=* domain.crossIntOut(NoCrossing, domain.tile.ceaseNode) + domain { + context.tileHaltXbarNode :=* domain.crossIntOut(NoCrossing, domain.element.haltNode) + context.tileWFIXbarNode :=* domain.crossIntOut(NoCrossing, domain.element.wfiNode) + context.tileCeaseXbarNode :=* domain.crossIntOut(NoCrossing, domain.element.ceaseNode) + } // TODO should context be forced to have a trace sink connected here? // for now this just ensures domain.trace[Core]Node has been crossed without connecting it externally - domain.crossTracesOut() } /** Connect inputs to the tile that are assumed to be constant during normal operation, and so are not clock-crossed. */ def connectInputConstants(domain: TilePRCIDomain[TileType], context: TileContextType): Unit = { implicit val p = context.p val tlBusToGetPrefixFrom = context.locateTLBusWrapper(crossingParams.mmioBaseAddressPrefixWhere) - domain.tile.hartIdNode := context.tileHartIdNode - domain.tile.resetVectorNode := context.tileResetVectorNode - tlBusToGetPrefixFrom.prefixNode.foreach { domain.tile.mmioAddressPrefixNode := _ } + domain.element.hartIdNode := context.tileHartIdNodes(domain.element.tileId) + domain.element.resetVectorNode := context.tileResetVectorNodes(domain.element.tileId) + tlBusToGetPrefixFrom.prefixNode.foreach { domain.element.mmioAddressPrefixNode := _ } } /** Connect power/reset/clock resources. */ @@ -362,19 +278,30 @@ trait CanAttachTile { case _: RationalCrossing => domain.clockNode := tlBusToGetClockDriverFrom.clockNode case _: AsynchronousCrossing => { val tileClockGroup = ClockGroup() - tileClockGroup := context.asyncClockGroupsNode + tileClockGroup := context.allClockGroupsNode domain.clockNode := tileClockGroup } }) domain { - domain.tile_reset_domain.clockNode := crossingParams.resetCrossingType.injectClockNode := domain.clockNode + domain.element_reset_domain.clockNode := crossingParams.resetCrossingType.injectClockNode := domain.clockNode } } + + /** Function to handle all trace crossings when tile is instantiated inside domains */ + def connectTrace(domain: TilePRCIDomain[TileType], context: TileContextType): Unit = { + implicit val p = context.p + val traceCrossingNode = BundleBridgeBlockDuringReset[TraceBundle]( + resetCrossingType = crossingParams.resetCrossingType) + context.traceNodes(domain.element.tileId) := traceCrossingNode := domain.element.traceNode + val traceCoreCrossingNode = BundleBridgeBlockDuringReset[TraceCoreInterface]( + resetCrossingType = crossingParams.resetCrossingType) + context.traceCoreNodes(domain.element.tileId) :*= traceCoreCrossingNode := domain.element.traceCoreNode + } } case class CloneTileAttachParams( - sourceHart: Int, + sourceTileId: Int, cloneParams: CanAttachTile ) extends CanAttachTile { type TileType = cloneParams.TileType @@ -382,78 +309,18 @@ case class CloneTileAttachParams( def tileParams = cloneParams.tileParams def crossingParams = cloneParams.crossingParams - require(sourceHart < tileParams.hartId) - override def instantiate(allTileParams: Seq[TileParams], instantiatedTiles: Seq[TilePRCIDomain[_]])(implicit p: Parameters): TilePRCIDomain[TileType] = { - val clockSinkParams = tileParams.clockSinkParams.copy(name = Some(s"${tileParams.name.getOrElse("core")}_${tileParams.hartId}")) + override def instantiate(allTileParams: Seq[TileParams], instantiatedTiles: SortedMap[Int, TilePRCIDomain[_]])(implicit p: Parameters): TilePRCIDomain[TileType] = { + require(instantiatedTiles.contains(sourceTileId)) + val clockSinkParams = tileParams.clockSinkParams.copy(name = Some(tileParams.uniqueName)) val tile_prci_domain = CloneLazyModule( new TilePRCIDomain[TileType](clockSinkParams, crossingParams) { self => - val tile = self.tile_reset_domain { LazyModule(tileParams.instantiate(crossingParams, PriorityMuxHartIdFromSeq(allTileParams))) } + val element = self.element_reset_domain { LazyModule(tileParams.instantiate(crossingParams, PriorityMuxHartIdFromSeq(allTileParams))) } }, - instantiatedTiles(sourceHart).asInstanceOf[TilePRCIDomain[TileType]] + instantiatedTiles(sourceTileId).asInstanceOf[TilePRCIDomain[TileType]] ) - tile_prci_domain - } -} - - -/** InstantiatesTiles adds a Config-urable sequence of tiles of any type - * to the subsystem class into which it is mixed. - */ -trait InstantiatesTiles { this: BaseSubsystem => - /** Record the order in which to instantiate all tiles, based on statically-assigned ids. - * - * Note that these ids, which are often used as the tiles' default hartid input, - * may or may not be those actually reflected at runtime in e.g. the $mhartid CSR - */ - val tileAttachParams: Seq[CanAttachTile] = p(TilesLocated(location)).sortBy(_.tileParams.hartId) - val tileParams: Seq[TileParams] = tileAttachParams.map(_.tileParams) - val tileCrossingTypes: Seq[ClockCrossingType] = tileAttachParams.map(_.crossingParams.crossingType) - - /** The actual list of instantiated tiles in this subsystem. */ - val tile_prci_domains: Seq[TilePRCIDomain[_]] = tileAttachParams.foldLeft(Seq[TilePRCIDomain[_]]()) { - case (instantiated, params) => instantiated :+ params.instantiate(tileParams, instantiated)(p) - } - - val tiles: Seq[BaseTile] = tile_prci_domains.map(_.tile.asInstanceOf[BaseTile]) - - // Helper functions for accessing certain parameters that are popular to refer to in subsystem code - def nTiles: Int = tileAttachParams.size - def hartIdList: Seq[Int] = tileParams.map(_.hartId) - def localIntCounts: Seq[Int] = tileParams.map(_.core.nLocalInterrupts) - - require(hartIdList.distinct.size == tiles.size, s"Every tile must be statically assigned a unique id, but got:\n${hartIdList}") -} - -/** HasTiles instantiates and also connects a Config-urable sequence of tiles of any type to subsystem interconnect resources. */ -trait HasTiles extends InstantiatesTiles with HasCoreMonitorBundles with DefaultTileContextType -{ this: BaseSubsystem => // TODO: ideally this bound would be softened to Attachable - implicit val p: Parameters - - // connect all the tiles to interconnect attachment points made available in this subsystem context - tileAttachParams.zip(tile_prci_domains).foreach { case (params, td) => - params.connect(td.asInstanceOf[TilePRCIDomain[params.TileType]], this.asInstanceOf[params.TileContextType]) + tile_prci_domain } } -/** Provides some Chisel connectivity to certain tile IOs */ -trait HasTilesModuleImp extends LazyModuleImp { - val outer: HasTiles with HasTileInterruptSources with HasTileInputConstants - - val reset_vector = outer.tileResetVectorIONodes.zipWithIndex.map { case (n, i) => n.makeIO(s"reset_vector_$i") } - val tile_hartids = outer.tileHartIdIONodes.zipWithIndex.map { case (n, i) => n.makeIO(s"tile_hartids_$i") } - val meip = if(outer.meipNode.isDefined) Some(IO(Input(Vec(outer.meipNode.get.out.size, Bool())))) else None - meip.foreach { m => - m.zipWithIndex.foreach{ case (pin, i) => - (outer.meipNode.get.out(i)._1)(0) := pin - } - } - val seip = if(outer.seipNode.isDefined) Some(IO(Input(Vec(outer.seipNode.get.out.size, Bool())))) else None - seip.foreach { s => - s.zipWithIndex.foreach{ case (pin, i) => - (outer.seipNode.get.out(i)._1)(0) := pin - } - } - val nmi = outer.tiles.zip(outer.tileNMIIONodes).zipWithIndex.map { case ((tile, n), i) => tile.tileParams.core.useNMI.option(n.makeIO(s"nmi_$i")) } -} diff --git a/src/main/scala/subsystem/HierarchicalElement.scala b/src/main/scala/subsystem/HierarchicalElement.scala new file mode 100644 index 00000000000..18a7c189f3e --- /dev/null +++ b/src/main/scala/subsystem/HierarchicalElement.scala @@ -0,0 +1,83 @@ +package freechips.rocketchip.subsystem + +import chisel3._ +import chisel3.util._ + +import org.chipsalliance.cde.config.Parameters +import freechips.rocketchip.diplomacy._ +import freechips.rocketchip.interrupts._ +import freechips.rocketchip.prci._ +import freechips.rocketchip.tile.{LookupByHartIdImpl, TraceBundle} +import freechips.rocketchip.subsystem._ +import freechips.rocketchip.tilelink._ +import freechips.rocketchip.util._ +import freechips.rocketchip.devices.debug.{TLDebugModule} +import freechips.rocketchip.devices.tilelink._ + +trait HierarchicalElementParams { + val baseName: String // duplicated instances shouuld share a base name + val uniqueName: String + val clockSinkParams: ClockSinkParameters +} + +abstract class InstantiableHierarchicalElementParams[ElementType <: BaseHierarchicalElement] extends HierarchicalElementParams + +/** An interface for describing the parameteization of how HierarchicalElements are connected to interconnects */ +trait HierarchicalElementCrossingParamsLike { + /** The type of clock crossing that should be inserted at the element boundary. */ + def crossingType: ClockCrossingType + /** Parameters describing the contents and behavior of the point where the element is attached as an interconnect master. */ + def master: HierarchicalElementPortParamsLike + /** Parameters describing the contents and behavior of the point where the element is attached as an interconnect slave. */ + def slave: HierarchicalElementPortParamsLike + /** The subnetwork location of the device selecting the apparent base address of MMIO devices inside the element */ + def mmioBaseAddressPrefixWhere: TLBusWrapperLocation + /** Inject a reset management subgraph that effects the element child reset only */ + def resetCrossingType: ResetCrossingType + /** Keep the element clock separate from the interconnect clock (e.g. even if they are synchronous to one another) */ + def forceSeparateClockReset: Boolean +} + +/** An interface for describing the parameterization of how a particular element port is connected to an interconnect */ +trait HierarchicalElementPortParamsLike { + /** The subnetwork location of the interconnect to which this element port should be connected. */ + def where: TLBusWrapperLocation + /** Allows port-specific adapters to be injected into the interconnect side of the attachment point. */ + def injectNode(context: Attachable)(implicit p: Parameters): TLNode +} + +abstract class BaseHierarchicalElement (val crossing: ClockCrossingType)(implicit p: Parameters) + extends LazyModule()(p) + with CrossesToOnlyOneClockDomain +{ + def module: BaseHierarchicalElementModuleImp[BaseHierarchicalElement] + + protected val tlOtherMastersNode = TLIdentityNode() + protected val tlMasterXbar = LazyModule(new TLXbar) + protected val tlSlaveXbar = LazyModule(new TLXbar) + protected val intXbar = LazyModule(new IntXbar) + + def masterNode: TLOutwardNode + def slaveNode: TLInwardNode + + /** Helper function to insert additional buffers on master ports at the boundary of the tile. + * + * The boundary buffering needed to cut feed-through paths is + * microarchitecture specific, so this may need to be overridden + * in subclasses of this class. + */ + def makeMasterBoundaryBuffers(crossing: ClockCrossingType)(implicit p: Parameters) = TLBuffer(BufferParams.none) + + /** Helper function to insert additional buffers on slave ports at the boundary of the tile. + * + * The boundary buffering needed to cut feed-through paths is + * microarchitecture specific, so this may need to be overridden + * in subclasses of this class. + */ + def makeSlaveBoundaryBuffers(crossing: ClockCrossingType)(implicit p: Parameters) = TLBuffer(BufferParams.none) + + +} + +abstract class BaseHierarchicalElementModuleImp[+L <: BaseHierarchicalElement](val outer: L) extends LazyModuleImp(outer) + diff --git a/src/main/scala/subsystem/HierarchicalElementPRCIDomain.scala b/src/main/scala/subsystem/HierarchicalElementPRCIDomain.scala new file mode 100644 index 00000000000..a76b7c43402 --- /dev/null +++ b/src/main/scala/subsystem/HierarchicalElementPRCIDomain.scala @@ -0,0 +1,96 @@ +package freechips.rocketchip.subsystem + +import chisel3._ +import chisel3.util._ + +import org.chipsalliance.cde.config.Parameters +import freechips.rocketchip.diplomacy._ +import freechips.rocketchip.interrupts._ +import freechips.rocketchip.prci._ +import freechips.rocketchip.tile.{RocketTile, TraceBundle} +import freechips.rocketchip.subsystem._ +import freechips.rocketchip.tilelink._ +import freechips.rocketchip.devices.debug.{TLDebugModule} +import freechips.rocketchip.devices.tilelink._ +import freechips.rocketchip.util.{TraceCoreInterface} + + +/** A wrapper containing all logic within a managed reset domain for a element. + * + * This does not add a layer of the module hierarchy. + */ +class HierarchicalElementResetDomain(clockSinkParams: ClockSinkParameters, resetCrossingType: ResetCrossingType) + (implicit p: Parameters) + extends ResetDomain + with CrossesToOnlyOneResetDomain +{ + def crossing = resetCrossingType + val clockNode = ClockSinkNode(Seq(clockSinkParams)) + def clockBundle = clockNode.in.head._1 + override def shouldBeInlined = true +} + +/** A wrapper containing all logic necessary to safely place a tile + * inside of a particular Power/Reset/Clock/Interrupt domain. + * + * This adds a layer to the module hierarchy which is a parent of the tile + * and should contain all logic related to clock crossings, isolation cells, + * hierarchical P&R boundary buffers, core-local interrupt handling, + * and any other IOs related to PRCI control. + */ +abstract class HierarchicalElementPRCIDomain[T <: BaseHierarchicalElement]( + clockSinkParams: ClockSinkParameters, + crossingParams: HierarchicalElementCrossingParamsLike) + (implicit p: Parameters) + extends ClockDomain +{ + val element: T + val element_reset_domain = LazyModule(new HierarchicalElementResetDomain(clockSinkParams, crossingParams.resetCrossingType)) + val tapClockNode = ClockIdentityNode() + val clockNode = FixedClockBroadcast() :=* tapClockNode + lazy val clockBundle = tapClockNode.in.head._1 + + /** External code looking to connect and clock-cross the interrupts driven into this tile can call this. */ + def crossIntIn(crossingType: ClockCrossingType, tileNode: IntInwardNode): IntInwardNode = { + // Unlike the other crossing helpers, here nothing is is blocked during reset because we know these are inputs and assume that tile reset is longer than uncore reset + val intInClockXing = this.crossIn(tileNode) + intInClockXing(crossingType) + } + + /** External code looking to connect and clock/reset-cross + * - interrupts raised by devices inside this tile + * - notifications raise by the cores and caches + * can call this function to instantiate the required crossing hardware. + * Takes crossingType as an argument because some interrupts are supposed to be synchronous + * Takes tileNode as an argument because tiles might have multiple outbound interrupt nodes + */ + def crossIntOut(crossingType: ClockCrossingType, tileNode: IntOutwardNode): IntOutwardNode = { + val intOutResetXing = this { element_reset_domain.crossIntOut(tileNode) } + val intOutClockXing = this.crossOut(intOutResetXing) + intOutClockXing(crossingType) + } + + /** External code looking to connect the ports where this tile is slaved to an interconnect + * (while also crossing clock domains) can call this. + */ + def crossSlavePort(crossingType: ClockCrossingType): TLInwardNode = { DisableMonitors { implicit p => FlipRendering { implicit p => + val tlSlaveResetXing = this { + element_reset_domain.crossTLIn(element.slaveNode) :*= + element { element.makeSlaveBoundaryBuffers(crossingType) } + } + val tlSlaveClockXing = this.crossIn(tlSlaveResetXing) + tlSlaveClockXing(crossingType) + } } } + + /** External code looking to connect the ports where this tile masters an interconnect + * (while also crossing clock domains) can call this. + */ + def crossMasterPort(crossingType: ClockCrossingType): TLOutwardNode = { + val tlMasterResetXing = this { DisableMonitors { implicit p => + element { element.makeMasterBoundaryBuffers(crossingType) } :=* + element_reset_domain.crossTLOut(element.masterNode) + } } + val tlMasterClockXing = this.crossOut(tlMasterResetXing) + tlMasterClockXing(crossingType) + } +} diff --git a/src/main/scala/subsystem/InterruptBus.scala b/src/main/scala/subsystem/InterruptBus.scala index e50f82a9ad5..2815e3f0866 100644 --- a/src/main/scala/subsystem/InterruptBus.scala +++ b/src/main/scala/subsystem/InterruptBus.scala @@ -45,7 +45,7 @@ abstract trait HasExtInterrupts { this: BaseSubsystem => */ trait HasAsyncExtInterrupts extends HasExtInterrupts { this: BaseSubsystem => if (nExtInterrupts > 0) { - ibus.fromAsync := extInterrupts + ibus { ibus.fromAsync := extInterrupts } } } @@ -54,7 +54,7 @@ trait HasAsyncExtInterrupts extends HasExtInterrupts { this: BaseSubsystem => */ trait HasSyncExtInterrupts extends HasExtInterrupts { this: BaseSubsystem => if (nExtInterrupts > 0) { - ibus.fromSync := extInterrupts + ibus { ibus.fromSync := extInterrupts } } } @@ -70,7 +70,7 @@ trait HasExtInterruptsBundle { /** This trait performs the translation from a UInt IO into Diplomatic Interrupts. * The wiring must be done in the concrete LazyModuleImp. */ -trait HasExtInterruptsModuleImp extends LazyModuleImp with HasExtInterruptsBundle { +trait HasExtInterruptsModuleImp extends LazyRawModuleImp with HasExtInterruptsBundle { val outer: HasExtInterrupts val interrupts = IO(Input(UInt(outer.nExtInterrupts.W))) diff --git a/src/main/scala/subsystem/LookupByClusterId.scala b/src/main/scala/subsystem/LookupByClusterId.scala new file mode 100644 index 00000000000..d0c5c21a5ab --- /dev/null +++ b/src/main/scala/subsystem/LookupByClusterId.scala @@ -0,0 +1,19 @@ +// See LICENSE.SiFive for license details. + +package freechips.rocketchip.subsystem + +import chisel3._ +import chisel3.util._ + +abstract class LookupByClusterIdImpl { + def apply[T <: Data](f: ClusterParams => Option[T], clusterId: UInt): T +} + +case class ClustersWontDeduplicate(t: ClusterParams) extends LookupByClusterIdImpl { + def apply[T <: Data](f: ClusterParams => Option[T], clusterId: UInt): T = f(t).get +} + +case class PriorityMuxClusterIdFromSeq(seq: Seq[ClusterParams]) extends LookupByClusterIdImpl { + def apply[T <: Data](f: ClusterParams => Option[T], clusterId: UInt): T = + PriorityMux(seq.collect { case t if f(t).isDefined => (t.clusterId.U === clusterId) -> f(t).get }) +} diff --git a/src/main/scala/subsystem/RTC.scala b/src/main/scala/subsystem/RTC.scala index 499633f679a..2c67d453577 100644 --- a/src/main/scala/subsystem/RTC.scala +++ b/src/main/scala/subsystem/RTC.scala @@ -4,26 +4,28 @@ package freechips.rocketchip.subsystem import chisel3._ import chisel3.util.Counter -import freechips.rocketchip.diplomacy.{LazyModuleImp, DTSTimebase} -import freechips.rocketchip.devices.tilelink.CanHavePeripheryCLINT +import freechips.rocketchip.diplomacy.{LazyRawModuleImp, DTSTimebase} +import freechips.rocketchip.devices.tilelink.{CLINTAttachKey, CanHavePeripheryCLINT} -trait HasRTCModuleImp extends LazyModuleImp { +trait HasRTCModuleImp extends LazyRawModuleImp { val outer: BaseSubsystem with CanHavePeripheryCLINT - private val pbusFreq = outer.p(PeripheryBusKey).dtsFrequency.get - private val rtcFreq = outer.p(DTSTimebase) - private val internalPeriod: BigInt = pbusFreq / rtcFreq - - val pbus = outer.locateTLBusWrapper(PBUS) - // check whether pbusFreq >= rtcFreq - require(internalPeriod > 0) - // check wehther the integer division is within 5% of the real division - require((pbusFreq - rtcFreq * internalPeriod) * 100 / pbusFreq <= 5) // Use the static period to toggle the RTC - chisel3.withClockAndReset(pbus.module.clock, pbus.module.reset) { - val (_, int_rtc_tick) = Counter(true.B, internalPeriod.toInt) - outer.clintOpt.foreach { clint => - clint.module.io.rtcTick := int_rtc_tick + outer.clintDomainOpt.map { domain => { + val bus = outer.locateTLBusWrapper(p(CLINTAttachKey).slaveWhere) + val busFreq = bus.dtsFrequency.get + val rtcFreq = outer.p(DTSTimebase) + val internalPeriod: BigInt = busFreq / rtcFreq + + + // check whether pbusFreq >= rtcFreq + require(internalPeriod > 0) + // check wehther the integer division is within 5% of the real division + require((busFreq - rtcFreq * internalPeriod) * 100 / busFreq <= 5) + + withClockAndReset (domain.module.clock, domain.module.reset) { + val (_, int_rtc_tick) = Counter(true.B, internalPeriod.toInt) + outer.clintTickOpt.foreach { _ := int_rtc_tick } } - } + }} } diff --git a/src/main/scala/subsystem/RocketSubsystem.scala b/src/main/scala/subsystem/RocketSubsystem.scala index e9e1f555515..ba70ab0c24a 100644 --- a/src/main/scala/subsystem/RocketSubsystem.scala +++ b/src/main/scala/subsystem/RocketSubsystem.scala @@ -7,32 +7,47 @@ import freechips.rocketchip.diplomacy._ import freechips.rocketchip.prci.{ResetCrossingType, NoResetCrossing} import freechips.rocketchip.tile._ import freechips.rocketchip.devices.debug.{HasPeripheryDebug} +import freechips.rocketchip.util.{HasCoreMonitorBundles} +import freechips.rocketchip.devices.tilelink.{CanHavePeripheryCLINT, CanHavePeripheryPLIC} case class RocketCrossingParams( crossingType: ClockCrossingType = SynchronousCrossing(), - master: TilePortParamsLike = TileMasterPortParams(), - slave: TileSlavePortParams = TileSlavePortParams(), + master: HierarchicalElementPortParamsLike = HierarchicalElementMasterPortParams(), + slave: HierarchicalElementSlavePortParams = HierarchicalElementSlavePortParams(), mmioBaseAddressPrefixWhere: TLBusWrapperLocation = CBUS, resetCrossingType: ResetCrossingType = NoResetCrossing(), forceSeparateClockReset: Boolean = false -) extends TileCrossingParamsLike +) extends HierarchicalElementCrossingParamsLike case class RocketTileAttachParams( tileParams: RocketTileParams, crossingParams: RocketCrossingParams ) extends CanAttachTile { type TileType = RocketTile } -trait HasRocketTiles extends HasTiles { this: BaseSubsystem => - val rocketTiles = tiles.collect { case r: RocketTile => r } +trait HasRocketTiles { + this: BaseSubsystem with InstantiatesHierarchicalElements => + val rocketTiles = totalTiles.values.collect { case r: RocketTile => r } def coreMonitorBundles = (rocketTiles map { t => t.module.core.rocketImpl.coreMonitorBundle }).toList } -class RocketSubsystem(implicit p: Parameters) extends BaseSubsystem with HasRocketTiles with HasPeripheryDebug { +class RocketSubsystem(implicit p: Parameters) extends BaseSubsystem + with InstantiatesHierarchicalElements + with HasTileNotificationSinks + with HasTileInputConstants + with CanHavePeripheryCLINT + with CanHavePeripheryPLIC + with HasPeripheryDebug + with HasHierarchicalElementsRootContext + with HasHierarchicalElements + with HasCoreMonitorBundles + with HasRocketTiles +{ override lazy val module = new RocketSubsystemModuleImp(this) } class RocketSubsystemModuleImp[+L <: RocketSubsystem](_outer: L) extends BaseSubsystemModuleImp(_outer) - with HasTilesModuleImp + with HasHierarchicalElementsRootContextModuleImp + diff --git a/src/main/scala/system/Configs.scala b/src/main/scala/system/Configs.scala index 9fb7debde82..9827cf428c0 100644 --- a/src/main/scala/system/Configs.scala +++ b/src/main/scala/system/Configs.scala @@ -34,6 +34,17 @@ class DualCoreConfig extends Config(new WithNBigCores(2) ++ new WithCoherentBusT class DualChannelConfig extends Config(new WithNMemoryChannels(2) ++ new DefaultConfig) class EightChannelConfig extends Config(new WithNMemoryChannels(8) ++ new DefaultConfig) +class ClusterConfig extends Config( + new WithNBigCores(2, InCluster(3)) ++ + new WithNBigCores(2, InCluster(1)) ++ + new WithNBigCores(2, InCluster(0)) ++ + new WithCluster(3, location=InCluster(2)) ++ + new WithCluster(2) ++ + new WithCluster(1) ++ + new WithCluster(0) ++ + new DefaultConfig +) + class DualChannelDualBankConfig extends Config( new WithNMemoryChannels(2) ++ new WithNBanks(4) ++ new DefaultConfig diff --git a/src/main/scala/system/TestHarness.scala b/src/main/scala/system/TestHarness.scala index a1e37dea169..788716258f1 100644 --- a/src/main/scala/system/TestHarness.scala +++ b/src/main/scala/system/TestHarness.scala @@ -16,8 +16,10 @@ class TestHarness()(implicit p: Parameters) extends Module { val ldut = LazyModule(new ExampleRocketSystem) val dut = Module(ldut.module) + ldut.io_clocks.get.elements.values.foreach(_.clock := clock) // Allow the debug ndreset to reset the dut, but not until the initial reset has completed - dut.reset := (reset.asBool | ldut.debug.map { debug => AsyncResetReg(debug.ndreset) }.getOrElse(false.B)).asBool + val dut_reset = (reset.asBool | ldut.debug.map { debug => AsyncResetReg(debug.ndreset) }.getOrElse(false.B)).asBool + ldut.io_clocks.get.elements.values.foreach(_.reset := dut_reset) dut.dontTouchPorts() dut.tieOffInterrupts() diff --git a/src/main/scala/tile/BaseTile.scala b/src/main/scala/tile/BaseTile.scala index 448050a0d50..76c8f7b1137 100644 --- a/src/main/scala/tile/BaseTile.scala +++ b/src/main/scala/tile/BaseTile.scala @@ -18,20 +18,19 @@ case object TileVisibilityNodeKey extends Field[TLEphemeralNode] case object TileKey extends Field[TileParams] case object LookupByHartId extends Field[LookupByHartIdImpl] -trait TileParams { +trait TileParams extends HierarchicalElementParams { val core: CoreParams val icache: Option[ICacheParams] val dcache: Option[DCacheParams] val btb: Option[BTBParams] - val hartId: Int - val beuAddr: Option[BigInt] + val tileId: Int // may not be hartid val blockerCtrlAddr: Option[BigInt] - val name: Option[String] - val clockSinkParams: ClockSinkParameters } -abstract class InstantiableTileParams[TileType <: BaseTile] extends TileParams { - def instantiate(crossing: TileCrossingParamsLike, lookup: LookupByHartIdImpl) +abstract class InstantiableTileParams[TileType <: BaseTile] + extends InstantiableHierarchicalElementParams[TileType] + with TileParams { + def instantiate(crossing: HierarchicalElementCrossingParamsLike, lookup: LookupByHartIdImpl) (implicit p: Parameters): TileType } @@ -77,15 +76,7 @@ trait HasNonDiplomaticTileParameters { xLen match { case 32 => 34; case 64 => 56 } } - /** Use staticIdForMetadataUseOnly to emit information during the build or identify a component to diplomacy. - * - * Including it in a constructed Chisel circuit by converting it to a UInt will prevent - * Chisel/FIRRTL from being able to deduplicate tiles that are otherwise homogeneous, - * a property which is important for hierarchical place & route flows. - */ - def staticIdForMetadataUseOnly: Int = tileParams.hartId - @deprecated("use hartIdSinkNodeOpt.map(_.bundle) or staticIdForMetadataUseOnly", "rocket-chip 1.3") - def hartId: Int = staticIdForMetadataUseOnly + def tileId: Int = tileParams.tileId def cacheBlockBytes = p(CacheBlockBytes) def lgCacheBlockBytes = log2Up(cacheBlockBytes) @@ -191,9 +182,8 @@ trait HasTileParameters extends HasNonDiplomaticTileParameters { } /** Base class for all Tiles that use TileLink */ -abstract class BaseTile private (val crossing: ClockCrossingType, q: Parameters) - extends LazyModule()(q) - with CrossesToOnlyOneClockDomain +abstract class BaseTile private (crossing: ClockCrossingType, q: Parameters) + extends BaseHierarchicalElement(crossing)(q) with HasNonDiplomaticTileParameters { // Public constructor alters Parameters to supply some legacy compatibility keys @@ -205,19 +195,12 @@ abstract class BaseTile private (val crossing: ClockCrossingType, q: Parameters) ))) } + def intInwardNode: IntInwardNode // Interrupts to the core from external devices + def intOutwardNode: Option[IntOutwardNode] // Interrupts from tile-internal devices (e.g. BEU) + def haltNode: IntOutwardNode // Unrecoverable error has occurred; suggest reset + def ceaseNode: IntOutwardNode // Tile has ceased to retire instructions + def wfiNode: IntOutwardNode // Tile is waiting for an interrupt def module: BaseTileModuleImp[BaseTile] - def masterNode: TLOutwardNode - def slaveNode: TLInwardNode - def intInwardNode: IntInwardNode // Interrupts to the core from external devices - def intOutwardNode: IntOutwardNode // Interrupts from tile-internal devices (e.g. BEU) - def haltNode: IntOutwardNode // Unrecoverable error has occurred; suggest reset - def ceaseNode: IntOutwardNode // Tile has ceased to retire instructions - def wfiNode: IntOutwardNode // Tile is waiting for an interrupt - - protected val tlOtherMastersNode = TLIdentityNode() - protected val tlMasterXbar = LazyModule(new TLXbar) - protected val tlSlaveXbar = LazyModule(new TLXbar) - protected val intXbar = LazyModule(new IntXbar) /** Node for broadcasting a hart id to diplomatic consumers within the tile. */ val hartIdNexusNode: BundleBridgeNode[UInt] = BundleBroadcast[UInt](registered = p(InsertTimingClosureRegistersOnHartIds)) @@ -250,10 +233,10 @@ abstract class BaseTile private (val crossing: ClockCrossingType, q: Parameters) resetVectorSinkNode := resetVectorNexusNode := BundleBridgeNameNode("reset_vector") /** Nodes for connecting NMI interrupt sources and vectors into the tile */ - val nmiNexusNode: BundleBridgeNode[NMI] = BundleBroadcast[NMI]() - val nmiSinkNode = BundleBridgeSink[NMI](Some(() => new NMI(visiblePhysAddrBits))) - val nmiNode: BundleBridgeInwardNode[NMI] = - nmiSinkNode := nmiNexusNode := BundleBridgeNameNode("nmi") + val nmiSinkNode = Option.when(tileParams.core.useNMI) { + BundleBridgeSink[NMI](Some(() => new NMI(visiblePhysAddrBits))) + } + val nmiNode: Option[BundleBridgeInwardNode[NMI]] = nmiSinkNode.map(_ := BundleBridgeNameNode("nmi")) /** Node for broadcasting an address prefix to diplomatic consumers within the tile. * @@ -279,15 +262,14 @@ abstract class BaseTile private (val crossing: ClockCrossingType, q: Parameters) protected def traceRetireWidth = tileParams.core.retireWidth /** Node for the core to drive legacy "raw" instruction trace. */ val traceSourceNode = BundleBridgeSource(() => new TraceBundle) - private val traceNexus = BundleBroadcast[TraceBundle]() // backwards compatiblity; not blocked during stretched reset /** Node for external consumers to source a legacy instruction trace from the core. */ - val traceNode: BundleBridgeOutwardNode[TraceBundle] = traceNexus := traceSourceNode + val traceNode = traceSourceNode - protected def traceCoreParams = new TraceCoreParams() + def traceCoreParams = new TraceCoreParams() /** Node for core to drive instruction trace conforming to RISC-V Processor Trace spec V1.0 */ val traceCoreSourceNode = BundleBridgeSource(() => new TraceCoreInterface(traceCoreParams)) /** Node for external consumers to source a V1.0 instruction trace from the core. */ - val traceCoreNode: BundleBridgeOutwardNode[TraceCoreInterface] = traceCoreSourceNode + val traceCoreNode = traceCoreSourceNode /** Node to broadcast collected trace sideband signals into the tile. */ val traceAuxNexusNode = BundleBridgeNexus[TraceAux](default = Some(() => { @@ -347,22 +329,6 @@ abstract class BaseTile private (val crossing: ClockCrossingType, q: Parameters) "hardware-exec-breakpoint-count" -> tileParams.core.nBreakpoints.asProperty ) - /** Helper function to insert additional buffers on master ports at the boundary of the tile. - * - * The boundary buffering needed to cut feed-through paths is - * microarchitecture specific, so this may need to be overridden - * in subclasses of this class. - */ - def makeMasterBoundaryBuffers(crossing: ClockCrossingType)(implicit p: Parameters) = TLBuffer(BufferParams.none) - - /** Helper function to insert additional buffers on slave ports at the boundary of the tile. - * - * The boundary buffering needed to cut feed-through paths is - * microarchitecture specific, so this may need to be overridden - * in subclasses of this class. - */ - def makeSlaveBoundaryBuffers(crossing: ClockCrossingType)(implicit p: Parameters) = TLBuffer(BufferParams.none) - /** Can be used to access derived params calculated by HasCoreParameters * * However, callers must ensure they do not access a diplomatically-determined parameter @@ -373,7 +339,7 @@ abstract class BaseTile private (val crossing: ClockCrossingType, q: Parameters) new C } - this.suggestName(tileParams.name) + this.suggestName(tileParams.baseName) } -abstract class BaseTileModuleImp[+L <: BaseTile](val outer: L) extends LazyModuleImp(outer) with HasTileParameters +abstract class BaseTileModuleImp[+L <: BaseTile](outer: L) extends BaseHierarchicalElementModuleImp[L](outer) diff --git a/src/main/scala/tile/Core.scala b/src/main/scala/tile/Core.scala index 8c9018da50a..dd3e0058bee 100644 --- a/src/main/scala/tile/Core.scala +++ b/src/main/scala/tile/Core.scala @@ -136,33 +136,9 @@ abstract class CoreModule(implicit val p: Parameters) extends Module abstract class CoreBundle(implicit val p: Parameters) extends ParameterizedBundle()(p) with HasCoreParameters -class CoreInterrupts(implicit p: Parameters) extends TileInterrupts()(p) { - val buserror = tileParams.beuAddr.map(a => Bool()) -} - // This is a raw commit trace from the core, not the TraceCoreInterface class TraceBundle(implicit val p: Parameters) extends Bundle with HasCoreParameters { val insns = Vec(coreParams.retireWidth, new TracedInstruction) val time = UInt(64.W) val custom = coreParams.traceCustom } - -trait HasCoreIO extends HasTileParameters { - implicit val p: Parameters - def nTotalRoCCCSRs: Int - val io = IO(new CoreBundle()(p) { - val hartid = Input(UInt(hartIdLen.W)) - val reset_vector = Input(UInt(resetVectorLen.W)) - val interrupts = Input(new CoreInterrupts()) - val imem = new FrontendIO - val dmem = new HellaCacheIO - val ptw = Flipped(new DatapathPTWIO()) - val fpu = Flipped(new FPUCoreIO()) - val rocc = Flipped(new RoCCCoreIO(nTotalRoCCCSRs)) - val trace = Output(new TraceBundle) - val bpwatch = Output(Vec(coreParams.nBreakpoints, new BPWatch(coreParams.retireWidth))) - val cease = Output(Bool()) - val wfi = Output(Bool()) - val traceStall = Input(Bool()) - }) -} diff --git a/src/main/scala/tile/LookupByHartId.scala b/src/main/scala/tile/LookupByHartId.scala index 263dd43c66f..631bb8f651e 100644 --- a/src/main/scala/tile/LookupByHartId.scala +++ b/src/main/scala/tile/LookupByHartId.scala @@ -10,10 +10,10 @@ abstract class LookupByHartIdImpl { } case class HartsWontDeduplicate(t: TileParams) extends LookupByHartIdImpl { - def apply[T <: Data](f: TileParams => Option[T], hartId: UInt): T = f(t).get + def apply[T <: Data](f: TileParams => Option[T], tileId: UInt): T = f(t).get } case class PriorityMuxHartIdFromSeq(seq: Seq[TileParams]) extends LookupByHartIdImpl { - def apply[T <: Data](f: TileParams => Option[T], hartId: UInt): T = - PriorityMux(seq.collect { case t if f(t).isDefined => (t.hartId.U === hartId) -> f(t).get }) + def apply[T <: Data](f: TileParams => Option[T], tileId: UInt): T = + PriorityMux(seq.collect { case t if f(t).isDefined => (t.tileId.U === tileId) -> f(t).get }) } diff --git a/src/main/scala/tile/RocketTile.scala b/src/main/scala/tile/RocketTile.scala index 930d803e392..9d4c460d68a 100644 --- a/src/main/scala/tile/RocketTile.scala +++ b/src/main/scala/tile/RocketTile.scala @@ -10,7 +10,7 @@ import freechips.rocketchip.diplomacy._ import freechips.rocketchip.interrupts._ import freechips.rocketchip.tilelink._ import freechips.rocketchip.rocket._ -import freechips.rocketchip.subsystem.TileCrossingParamsLike +import freechips.rocketchip.subsystem.HierarchicalElementCrossingParamsLike import freechips.rocketchip.util._ import freechips.rocketchip.prci.{ClockSinkParameters} @@ -22,8 +22,7 @@ case class RocketTileParams( dcache: Option[DCacheParams] = Some(DCacheParams()), btb: Option[BTBParams] = Some(BTBParams()), dataScratchpadBytes: Int = 0, - name: Option[String] = Some("tile"), - hartId: Int = 0, + tileId: Int = 0, beuAddr: Option[BigInt] = None, blockerCtrlAddr: Option[BigInt] = None, clockSinkParams: ClockSinkParameters = ClockSinkParameters(), @@ -31,7 +30,9 @@ case class RocketTileParams( ) extends InstantiableTileParams[RocketTile] { require(icache.isDefined) require(dcache.isDefined) - def instantiate(crossing: TileCrossingParamsLike, lookup: LookupByHartIdImpl)(implicit p: Parameters): RocketTile = { + val baseName = "rockettile" + val uniqueName = s"${baseName}_$tileId" + def instantiate(crossing: HierarchicalElementCrossingParamsLike, lookup: LookupByHartIdImpl)(implicit p: Parameters): RocketTile = { new RocketTile(this, crossing, lookup) } } @@ -49,10 +50,10 @@ class RocketTile private( with HasICacheFrontend { // Private constructor ensures altered LazyModule.p is used implicitly - def this(params: RocketTileParams, crossing: TileCrossingParamsLike, lookup: LookupByHartIdImpl)(implicit p: Parameters) = + def this(params: RocketTileParams, crossing: HierarchicalElementCrossingParamsLike, lookup: LookupByHartIdImpl)(implicit p: Parameters) = this(params, crossing.crossingType, lookup, p) - val intOutwardNode = IntIdentityNode() + val intOutwardNode = rocketParams.beuAddr map { _ => IntIdentityNode() } val slaveNode = TLIdentityNode() val masterNode = visibilityNode @@ -63,7 +64,7 @@ class RocketTile private( val bus_error_unit = rocketParams.beuAddr map { a => val beu = LazyModule(new BusErrorUnit(new L1BusErrors, BusErrorUnitParams(a))) - intOutwardNode := beu.intNode + intOutwardNode.get := beu.intNode connectTLSlave(beu.node, xBytes) beu } @@ -100,7 +101,7 @@ class RocketTile private( } ResourceBinding { - Resource(cpuDevice, "reg").bind(ResourceAddress(staticIdForMetadataUseOnly)) + Resource(cpuDevice, "reg").bind(ResourceAddress(tileId)) } override lazy val module = new RocketTileModuleImp(this) @@ -149,7 +150,7 @@ class RocketTileModuleImp(outer: RocketTile) extends BaseTileModuleImp(outer) beu.module.io.errors.icache := outer.frontend.module.io.errors } - core.io.interrupts.nmi.foreach { nmi => nmi := outer.nmiSinkNode.bundle } + core.io.interrupts.nmi.foreach { nmi => nmi := outer.nmiSinkNode.get.bundle } // Pass through various external constants and reports that were bundle-bridged into the tile outer.traceSourceNode.bundle <> core.io.trace diff --git a/src/main/scala/tile/TilePRCIDomain.scala b/src/main/scala/tile/TilePRCIDomain.scala index 73972bec4de..d4066a63473 100644 --- a/src/main/scala/tile/TilePRCIDomain.scala +++ b/src/main/scala/tile/TilePRCIDomain.scala @@ -8,24 +8,10 @@ import freechips.rocketchip.diplomacy._ import freechips.rocketchip.interrupts._ import freechips.rocketchip.prci._ import freechips.rocketchip.rocket.{TracedInstruction} -import freechips.rocketchip.subsystem.{TileCrossingParamsLike, CrossesToOnlyOneResetDomain} +import freechips.rocketchip.subsystem._ import freechips.rocketchip.tilelink._ import freechips.rocketchip.util.{TraceCoreInterface} -/** A wrapper containing all logic within a managed reset domain for a tile. - * - * This does not add a layer of the module hierarchy. - */ -class TileResetDomain(clockSinkParams: ClockSinkParameters, resetCrossingType: ResetCrossingType) - (implicit p: Parameters) - extends ResetDomain - with CrossesToOnlyOneResetDomain -{ - def crossing = resetCrossingType - val clockNode = ClockSinkNode(Seq(clockSinkParams)) - def clockBundle = clockNode.in.head._1 - override def shouldBeInlined = true -} /** A wrapper containing all logic necessary to safely place a tile * inside of a particular Power/Reset/Clock/Interrupt domain. @@ -37,77 +23,9 @@ class TileResetDomain(clockSinkParams: ClockSinkParameters, resetCrossingType: R */ abstract class TilePRCIDomain[T <: BaseTile]( clockSinkParams: ClockSinkParameters, - crossingParams: TileCrossingParamsLike) + crossingParams: HierarchicalElementCrossingParamsLike) (implicit p: Parameters) - extends ClockDomain + extends HierarchicalElementPRCIDomain[T](clockSinkParams, crossingParams) { - val tile: T - val tile_reset_domain = LazyModule(new TileResetDomain(clockSinkParams, crossingParams.resetCrossingType)) - val tapClockNode = ClockIdentityNode() - val clockNode = FixedClockBroadcast(None) :=* tapClockNode - lazy val clockBundle = tapClockNode.in.head._1 - - private val traceSignalName = "trace" - private val traceCoreSignalName = "tracecore" - /** Node to broadcast legacy "raw" instruction trace while surpressing it during (async) reset. */ - val traceNode: BundleBridgeIdentityNode[TraceBundle] = BundleBridgeNameNode(traceSignalName) - /** Node to broadcast standardized instruction trace while surpressing it during (async) reset. */ - val traceCoreNode: BundleBridgeIdentityNode[TraceCoreInterface] = BundleBridgeNameNode(traceCoreSignalName) - - /** Function to handle all trace crossings when tile is instantiated inside domains */ - def crossTracesOut(): Unit = this { - val traceNexusNode = BundleBridgeBlockDuringReset[TraceBundle]( - resetCrossingType = crossingParams.resetCrossingType, - name = Some(traceSignalName)) - traceNode :*= traceNexusNode := tile.traceNode - - val traceCoreNexusNode = BundleBridgeBlockDuringReset[TraceCoreInterface]( - resetCrossingType = crossingParams.resetCrossingType, - name = Some(traceCoreSignalName)) - traceCoreNode :*= traceCoreNexusNode := tile.traceCoreNode - } - - /** External code looking to connect and clock-cross the interrupts driven into this tile can call this. */ - def crossIntIn(crossingType: ClockCrossingType): IntInwardNode = { - // Unlike the other crossing helpers, here nothing is is blocked during reset because we know these are inputs and assume that tile reset is longer than uncore reset - val intInClockXing = this.crossIn(tile.intInwardNode) - intInClockXing(crossingType) - } - - /** External code looking to connect and clock/reset-cross - * - interrupts raised by devices inside this tile - * - notifications raise by the cores and caches - * can call this function to instantiate the required crossing hardware. - * Takes crossingType as an argument because some interrupts are supposed to be synchronous - * Takes tileNode as an argument because tiles might have multiple outbound interrupt nodes - */ - def crossIntOut(crossingType: ClockCrossingType, tileNode: IntOutwardNode): IntOutwardNode = { - val intOutResetXing = this { tile_reset_domain.crossIntOut(tileNode) } - val intOutClockXing = this.crossOut(intOutResetXing) - intOutClockXing(crossingType) - } - - /** External code looking to connect the ports where this tile is slaved to an interconnect - * (while also crossing clock domains) can call this. - */ - def crossSlavePort(crossingType: ClockCrossingType): TLInwardNode = { DisableMonitors { implicit p => FlipRendering { implicit p => - val tlSlaveResetXing = this { - tile_reset_domain.crossTLIn(tile.slaveNode) :*= - tile { tile.makeSlaveBoundaryBuffers(crossingType) } - } - val tlSlaveClockXing = this.crossIn(tlSlaveResetXing) - tlSlaveClockXing(crossingType) - } } } - - /** External code looking to connect the ports where this tile masters an interconnect - * (while also crossing clock domains) can call this. - */ - def crossMasterPort(crossingType: ClockCrossingType): TLOutwardNode = { - val tlMasterResetXing = this { DisableMonitors { implicit p => - tile { tile.makeMasterBoundaryBuffers(crossingType) } :=* - tile_reset_domain.crossTLOut(tile.masterNode) - } } - val tlMasterClockXing = this.crossOut(tlMasterResetXing) - tlMasterClockXing(crossingType) - } + def tile_reset_domain = element_reset_domain } diff --git a/src/main/scala/tilelink/BusWrapper.scala b/src/main/scala/tilelink/BusWrapper.scala index 657bba873f6..b07844cef6a 100644 --- a/src/main/scala/tilelink/BusWrapper.scala +++ b/src/main/scala/tilelink/BusWrapper.scala @@ -72,6 +72,11 @@ abstract class TLBusWrapper(params: HasTLBusParams, val busName: String)(implici def unifyManagers: List[TLManagerParameters] = ManagerUnification(busView.manager.managers) def crossOutHelper = this.crossOut(outwardNode)(ValName("bus_xing")) def crossInHelper = this.crossIn(inwardNode)(ValName("bus_xing")) + def generateSynchronousDomain: ClockSinkDomain = { + val domain = LazyModule(new ClockSinkDomain(take = fixedClockOpt)) + domain.clockNode := fixedClockNode + domain + } protected val addressPrefixNexusNode = BundleBroadcast[UInt](registered = false, default = Some(() => 0.U(1.W))) @@ -89,15 +94,15 @@ abstract class TLBusWrapper(params: HasTLBusParams, val busName: String)(implici def coupleFrom[T](name: String)(gen: TLInwardNode => T): T = from(name) { gen(inwardNode :*=* TLNameNode("tl")) } - def crossToBus(bus: TLBusWrapper, xType: ClockCrossingType)(implicit asyncClockGroupNode: ClockGroupEphemeralNode): NoHandle = { - bus.clockGroupNode := asyncMux(xType, asyncClockGroupNode, this.clockGroupNode) + def crossToBus(bus: TLBusWrapper, xType: ClockCrossingType, allClockGroupNode: ClockGroupEphemeralNode): NoHandle = { + bus.clockGroupNode := asyncMux(xType, allClockGroupNode, this.clockGroupNode) coupleTo(s"bus_named_${bus.busName}") { bus.crossInHelper(xType) :*= TLWidthWidget(beatBytes) :*= _ } } - def crossFromBus(bus: TLBusWrapper, xType: ClockCrossingType)(implicit asyncClockGroupNode: ClockGroupEphemeralNode): NoHandle = { - bus.clockGroupNode := asyncMux(xType, asyncClockGroupNode, this.clockGroupNode) + def crossFromBus(bus: TLBusWrapper, xType: ClockCrossingType, allClockGroupNode: ClockGroupEphemeralNode): NoHandle = { + bus.clockGroupNode := asyncMux(xType, allClockGroupNode, this.clockGroupNode) coupleFrom(s"bus_named_${bus.busName}") { _ :=* TLWidthWidget(bus.beatBytes) :=* bus.crossOutHelper(xType) } @@ -178,8 +183,8 @@ class TLBusWrapperConnection val masterTLBus = context.locateTLBusWrapper(master) val slaveTLBus = context.locateTLBusWrapper(slave) def bindClocks(implicit p: Parameters) = driveClockFromMaster match { - case Some(true) => slaveTLBus.clockGroupNode := asyncMux(xType, context.asyncClockGroupsNode, masterTLBus.clockGroupNode) - case Some(false) => masterTLBus.clockGroupNode := asyncMux(xType, context.asyncClockGroupsNode, slaveTLBus.clockGroupNode) + case Some(true) => slaveTLBus.clockGroupNode := asyncMux(xType, context.allClockGroupsNode, masterTLBus.clockGroupNode) + case Some(false) => masterTLBus.clockGroupNode := asyncMux(xType, context.allClockGroupsNode, slaveTLBus.clockGroupNode) case None => } def bindTLNodes(implicit p: Parameters) = nodeBinding match { @@ -240,8 +245,8 @@ case class AddressAdjusterWrapperParams( { val dtsFrequency = None def instantiate(context: HasTileLinkLocations, loc: Location[TLBusWrapper])(implicit p: Parameters): AddressAdjusterWrapper = { - val aaWrapper = LazyModule(new AddressAdjusterWrapper(this, loc.name)) - aaWrapper.suggestName(loc.name + "_wrapper") + val aaWrapper = LazyModule(new AddressAdjusterWrapper(this, context.busContextName + "_" + loc.name)) + aaWrapper.suggestName(context.busContextName + "_" + loc.name + "_wrapper") context.tlBusWrapperLocationMap += (loc -> aaWrapper) aaWrapper } @@ -270,8 +275,8 @@ case class TLJBarWrapperParams( { val dtsFrequency = None def instantiate(context: HasTileLinkLocations, loc: Location[TLBusWrapper])(implicit p: Parameters): TLJBarWrapper = { - val jbarWrapper = LazyModule(new TLJBarWrapper(this, loc.name)) - jbarWrapper.suggestName(loc.name + "_wrapper") + val jbarWrapper = LazyModule(new TLJBarWrapper(this, context.busContextName + "_" + loc.name)) + jbarWrapper.suggestName(context.busContextName + "_" + loc.name + "_wrapper") context.tlBusWrapperLocationMap += (loc -> jbarWrapper) jbarWrapper } diff --git a/src/main/scala/tilelink/Monitor.scala b/src/main/scala/tilelink/Monitor.scala index f34e388e54c..013912a562d 100644 --- a/src/main/scala/tilelink/Monitor.scala +++ b/src/main/scala/tilelink/Monitor.scala @@ -587,7 +587,7 @@ class TLMonitor(args: TLMonitorArgs, monitorDir: MonitorDirection = MonitorDirec } if (edge.manager.minLatency > 0) { - assume(a_set =/= d_clr || !a_set.orR, s"'A' and 'D' concurrent, despite minlatency ${edge.manager.minLatency}" + extra) + assume(a_set =/= d_clr || !a_set.orR, s"'A' and 'D' concurrent, despite minlatency > 0" + extra) } inflight := (inflight | a_set) & ~d_clr @@ -696,7 +696,7 @@ class TLMonitor(args: TLMonitorArgs, monitorDir: MonitorDirection = MonitorDirec } if (edge.manager.minLatency > 0) { - assume(a_set_wo_ready =/= d_clr_wo_ready || !a_set_wo_ready.orR, s"'A' and 'D' concurrent, despite minlatency ${edge.manager.minLatency}" + extra) + assume(a_set_wo_ready =/= d_clr_wo_ready || !a_set_wo_ready.orR, s"'A' and 'D' concurrent, despite minlatency > 0" + extra) } inflight := (inflight | a_set) & ~d_clr @@ -804,7 +804,7 @@ class TLMonitor(args: TLMonitorArgs, monitorDir: MonitorDirection = MonitorDirec if (edge.manager.minLatency > 0) { when (c_set_wo_ready.orR) { - assume(c_set_wo_ready =/= d_clr_wo_ready, s"'C' and 'D' concurrent, despite minlatency ${edge.manager.minLatency}" + extra) + assume(c_set_wo_ready =/= d_clr_wo_ready, s"'C' and 'D' concurrent, despite minlatency > 0" + extra) } }