diff --git a/src/main/scala/coreplex/BaseCoreplex.scala b/src/main/scala/coreplex/BaseCoreplex.scala index bba04d0d..be23ee83 100644 --- a/src/main/scala/coreplex/BaseCoreplex.scala +++ b/src/main/scala/coreplex/BaseCoreplex.scala @@ -5,11 +5,8 @@ package freechips.rocketchip.coreplex import Chisel._ import freechips.rocketchip.config.Parameters import freechips.rocketchip.diplomacy._ -import freechips.rocketchip.interrupts._ import freechips.rocketchip.tilelink._ import freechips.rocketchip.devices.tilelink._ -import freechips.rocketchip.tile.{BaseTile, TileParams, SharedMemoryTLEdge, HasExternallyDrivenTileConstants} -import freechips.rocketchip.devices.debug.{HasPeripheryDebug, HasPeripheryDebugModuleImp} import freechips.rocketchip.util._ /** BareCoreplex is the root class for creating a coreplex sub-system */ @@ -27,25 +24,6 @@ abstract class BareCoreplexModule[+L <: BareCoreplex](_outer: L) extends LazyMod println(outer.dts) } -trait HasTiles extends HasSystemBus { - protected def tileParams: Seq[TileParams] - def nRocketTiles = tileParams.size - def hartIdList = tileParams.map(_.hartid) - - // Handle interrupts to be routed directly into each tile - // TODO: figure out how to merge the localIntNodes and coreIntXbar - def localIntCounts = tileParams.map(_.core.nLocalInterrupts) - lazy val localIntNodes = tileParams.zipWithIndex map { case (t, i) => { - (t.core.nLocalInterrupts > 0).option({ - val n = LazyModule(new IntXbar) - n.suggestName(s"localIntXbar_${i}") - n.intnode}) - } - } - - val tiles: Seq[BaseTile] -} - /** Base Coreplex class with no peripheral devices or ports added */ abstract class BaseCoreplex(implicit p: Parameters) extends BareCoreplex with HasInterruptBus @@ -80,46 +58,6 @@ abstract class BaseCoreplex(implicit p: Parameters) extends BareCoreplex } } -class ClockedTileInputs(implicit val p: Parameters) extends ParameterizedBundle - with HasExternallyDrivenTileConstants - with Clocked - -trait HasTilesBundle { - val tile_inputs: Vec[ClockedTileInputs] -} - -trait HasTilesModuleImp extends LazyModuleImp - with HasTilesBundle - with HasResetVectorWire { - val outer: HasTiles - - def resetVectorBits: Int = { - // Consider using the minimum over all widths, rather than enforcing homogeneity - val vectors = outer.tiles.map(_.module.io.reset_vector) - require(vectors.tail.forall(_.getWidth == vectors.head.getWidth)) - vectors.head.getWidth - } - val tile_inputs = Wire(Vec(outer.nRocketTiles, new ClockedTileInputs()(p.alterPartial { - case SharedMemoryTLEdge => outer.sharedMemoryTLEdge - }))) - - // Unconditionally wire up the non-diplomatic tile inputs - outer.tiles.map(_.module).zip(tile_inputs).foreach { case(tile, wire) => - tile.clock := wire.clock - tile.reset := wire.reset - tile.io.hartid := wire.hartid - tile.io.reset_vector := wire.reset_vector - } - - // Default values for tile inputs; may be overriden in other traits - tile_inputs.zip(outer.hartIdList).foreach { case(wire, i) => - wire.clock := clock - wire.reset := reset - wire.hartid := UInt(i) - wire.reset_vector := global_reset_vector - } -} - abstract class BaseCoreplexModule[+L <: BaseCoreplex](_outer: L) extends BareCoreplexModule(_outer) { println("Generated Address Map") private val aw = (outer.sharedMemoryTLEdge.bundle.addressBits-1)/4 + 1 diff --git a/src/main/scala/coreplex/Configs.scala b/src/main/scala/coreplex/Configs.scala index 00c024c4..ab6d6fa7 100644 --- a/src/main/scala/coreplex/Configs.scala +++ b/src/main/scala/coreplex/Configs.scala @@ -45,7 +45,7 @@ class WithNBigCores(n: Int) extends Config((site, here, up) => { icache = Some(ICacheParams( rowBits = site(SystemBusKey).beatBits, blockBytes = site(CacheBlockBytes)))) - List.tabulate(n)(i => big.copy(hartid = i)) + List.tabulate(n)(i => big.copy(hartId = i)) } }) @@ -67,7 +67,7 @@ class WithNSmallCores(n: Int) extends Config((site, here, up) => { nWays = 1, nTLBEntries = 4, blockBytes = site(CacheBlockBytes)))) - List.tabulate(n)(i => small.copy(hartid = i)) + List.tabulate(n)(i => small.copy(hartId = i)) } }) diff --git a/src/main/scala/coreplex/HasTiles.scala b/src/main/scala/coreplex/HasTiles.scala new file mode 100644 index 00000000..82436651 --- /dev/null +++ b/src/main/scala/coreplex/HasTiles.scala @@ -0,0 +1,52 @@ +// See LICENSE.SiFive for license details. + +package freechips.rocketchip.coreplex + +import Chisel._ +import freechips.rocketchip.config.Parameters +import freechips.rocketchip.diplomacy._ +import freechips.rocketchip.interrupts._ +import freechips.rocketchip.tile.{BaseTile, TileParams, SharedMemoryTLEdge, HasExternallyDrivenTileConstants} +import freechips.rocketchip.util._ + +class ClockedTileInputs(implicit val p: Parameters) extends ParameterizedBundle + with HasExternallyDrivenTileConstants + with Clocked + +trait HasTiles extends HasSystemBus { + val tiles: Seq[BaseTile] + protected def tileParams: Seq[TileParams] = tiles.map(_.tileParams) + def nTiles: Int = tileParams.size + def hartIdList: Seq[Int] = tileParams.map(_.hartId) + def localIntCounts: Seq[Int] = tileParams.map(_.core.nLocalInterrupts) +} + +trait HasTilesBundle { + val tile_inputs: Vec[ClockedTileInputs] +} + +trait HasTilesModuleImp extends LazyModuleImp + with HasTilesBundle + with HasResetVectorWire { + val outer: HasTiles + + def resetVectorBits: Int = { + // Consider using the minimum over all widths, rather than enforcing homogeneity + val vectors = outer.tiles.map(_.module.constants.reset_vector) + require(vectors.tail.forall(_.getWidth == vectors.head.getWidth)) + vectors.head.getWidth + } + + val tile_inputs = Wire(Vec(outer.nTiles, new ClockedTileInputs()(p.alterPartial { + case SharedMemoryTLEdge => outer.sharedMemoryTLEdge + }))) + + // Unconditionally wire up the non-diplomatic tile inputs + outer.tiles.map(_.module).zip(tile_inputs).foreach { case(tile, wire) => + tile.clock := wire.clock + tile.reset := wire.reset + tile.constants.hartid := wire.hartid + tile.constants.reset_vector := wire.reset_vector + } +} + diff --git a/src/main/scala/coreplex/RocketCoreplex.scala b/src/main/scala/coreplex/RocketCoreplex.scala index 2860a9fd..a070123b 100644 --- a/src/main/scala/coreplex/RocketCoreplex.scala +++ b/src/main/scala/coreplex/RocketCoreplex.scala @@ -67,37 +67,69 @@ trait HasRocketTiles extends HasTiles with HasPeripheryDebug { val module: HasRocketTilesModuleImp - protected val tileParams = p(RocketTilesKey) - private val NumRocketTiles = tileParams.size + protected val rocketTileParams = p(RocketTilesKey) + private val NumRocketTiles = rocketTileParams.size private val crossingParams = p(RocketCrossingKey) private val crossings = crossingParams.size match { case 1 => List.fill(NumRocketTiles) { crossingParams.head } case NumRocketTiles => crossingParams case _ => throw new Exception("RocketCrossingKey.size must == 1 or == RocketTilesKey.size") } - private val crossingTuples = localIntNodes.zip(tileParams).zip(crossings) + private val crossingTuples = rocketTileParams.zip(crossings) - // Make a wrapper for each tile that will wire it to coreplex devices and crossbars, + // Make a tile and wire its nodes into the system, // according to the specified type of clock crossing. - val tiles: Seq[BaseTile] = crossingTuples.map { case ((lip, tp), crossing) => + // Note that we also inject new nodes into the tile itself, + // also based on the crossing type. + val rocketTiles = crossingTuples.map { case (tp, crossing) => // For legacy reasons, it is convenient to store some state // in the global Parameters about the specific tile being built now - val wrapper = LazyModule(new RocketTileWrapper( - params = tp, - crossing = crossing.crossingType - )(p.alterPartial { + val rocket = LazyModule(new RocketTile(tp, crossing.crossingType)(p.alterPartial { case TileKey => tp case BuildRoCC => tp.rocc case SharedMemoryTLEdge => sharedMemoryTLEdge - case RocketCrossingKey => List(crossing) }) ).suggestName(tp.name) // Connect the master ports of the tile to the system bus - sbus.fromTile(tp.name) { implicit p => crossing.master.adapt(this)(wrapper.crossTLOut :=* wrapper.masterNode) } + + def tileMasterBuffering: TLOutwardNode = rocket { + // The buffers needed to cut feed-through paths are microarchitecture specific, so belong here + val masterBuffer = LazyModule(new TLBuffer(BufferParams.none, BufferParams.flow, BufferParams.none, BufferParams.flow, BufferParams(1))) + crossing.crossingType match { + case _: AsynchronousCrossing => rocket.masterNode + case SynchronousCrossing(b) => + require (!tp.boundaryBuffers || (b.depth >= 1 && !b.flow && !b.pipe), "Buffer misconfiguration creates feed-through paths") + rocket.masterNode + case RationalCrossing(dir) => + require (dir != SlowToFast, "Misconfiguration? Core slower than fabric") + if (tp.boundaryBuffers) { + masterBuffer.node :=* rocket.masterNode + } else { + rocket.masterNode + } + } + } + + sbus.fromTile(tp.name) { implicit p => crossing.master.adapt(this)(rocket.crossTLOut :=* tileMasterBuffering) } // Connect the slave ports of the tile to the periphery bus - pbus.toTile(tp.name) { implicit p => crossing.slave.adapt(this)(wrapper.slaveNode :*= wrapper.crossTLIn) } + + def tileSlaveBuffering: TLInwardNode = rocket { + val slaveBuffer = LazyModule(new TLBuffer(BufferParams.flow, BufferParams.none, BufferParams.none, BufferParams.none, BufferParams.none)) + crossing.crossingType match { + case _: SynchronousCrossing => rocket.slaveNode // requirement already checked + case _: AsynchronousCrossing => rocket.slaveNode + case _: RationalCrossing => + if (tp.boundaryBuffers) { + DisableMonitors { implicit p => rocket.slaveNode :*= slaveBuffer.node } + } else { + rocket.slaveNode + } + } + } + + pbus.toTile(tp.name) { implicit p => crossing.slave.adapt(this)(tileSlaveBuffering :*= rocket.crossTLIn) } // Handle all the different types of interrupts crossing to or from the tile: // 1. Debug interrupt is definitely asynchronous in all cases. @@ -109,24 +141,24 @@ trait HasRocketTiles extends HasTiles // NOTE: The order of calls to := matters! They must match how interrupts // are decoded from rocket.intNode inside the tile. - wrapper.intXbar.intnode := wrapper { IntSyncCrossingSink(3) } := debug.intnode // 1. always async crossign + // 1. always async crossing for debug + rocket.intInwardNode := rocket { IntSyncCrossingSink(3) } := debug.intnode - // 2. clint+plic conditionak crossing - val periphIntNode = wrapper.intXbar.intnode :=* wrapper.crossIntIn + // 2. clint+plic conditionally crossing + val periphIntNode = rocket.intInwardNode :=* rocket.crossIntIn periphIntNode := clint.intnode // msip+mtip periphIntNode := plic.intnode // meip if (tp.core.useVM) periphIntNode := plic.intnode // seip - lip.foreach { wrapper.intXbar.intnode := _ } // 3. lip never crosses + // 3. local interrupts never cross + // this.intInwardNode is wired up externally // lip - // From core to PLIC - wrapper.rocket.intOutputNode.foreach { i => // 4. conditional crossing - FlipRendering { implicit p => - plic.intnode :=* wrapper.crossIntOut :=* i - } + // 4. conditional crossing from core to PLIC + FlipRendering { implicit p => + plic.intnode :=* rocket.crossIntOut :=* rocket.intOutwardNode } - wrapper + rocket } } @@ -137,8 +169,16 @@ trait HasRocketTilesModuleImp extends HasTilesModuleImp class RocketCoreplex(implicit p: Parameters) extends BaseCoreplex with HasRocketTiles { + val tiles = rocketTiles override lazy val module = new RocketCoreplexModule(this) } class RocketCoreplexModule[+L <: RocketCoreplex](_outer: L) extends BaseCoreplexModule(_outer) - with HasRocketTilesModuleImp + with HasRocketTilesModuleImp { + tile_inputs.zip(outer.hartIdList).foreach { case(wire, i) => + wire.clock := clock + wire.reset := reset + wire.hartid := UInt(i) + wire.reset_vector := global_reset_vector + } +} diff --git a/src/main/scala/diplomacy/SRAM.scala b/src/main/scala/diplomacy/SRAM.scala index 8add66d4..d0b700f8 100644 --- a/src/main/scala/diplomacy/SRAM.scala +++ b/src/main/scala/diplomacy/SRAM.scala @@ -10,9 +10,11 @@ abstract class DiplomaticSRAM( beatBytes: Int, devName: Option[String])(implicit p: Parameters) extends LazyModule { - protected val resources = devName - .map(new SimpleDevice(_, Seq("sifive,sram0")).reg("mem")) - .getOrElse(new MemoryDevice().reg) + val device = devName + .map(new SimpleDevice(_, Seq("sifive,sram0"))) + .getOrElse(new MemoryDevice()) + + val resources = device.reg("mem") def bigBits(x: BigInt, tail: List[Boolean] = Nil): List[Boolean] = if (x == 0) tail.reverse else bigBits(x >> 1, ((x & 1) == 1) :: tail) diff --git a/src/main/scala/diplomacy/package.scala b/src/main/scala/diplomacy/package.scala index 3f175f32..7fcfeff8 100644 --- a/src/main/scala/diplomacy/package.scala +++ b/src/main/scala/diplomacy/package.scala @@ -31,6 +31,25 @@ package object diplomacy } } + type PropertyOption = Option[(String, Seq[ResourceValue])] + type PropertyMap = Iterable[(String, Seq[ResourceValue])] + + implicit class IntToProperty(x: Int) { + def asProperty: Seq[ResourceValue] = Seq(ResourceInt(BigInt(x))) + } + + implicit class BigIntToProperty(x: BigInt) { + def asProperty: Seq[ResourceValue] = Seq(ResourceInt(x)) + } + + implicit class StringToProperty(x: String) { + def asProperty: Seq[ResourceValue] = Seq(ResourceString(x)) + } + + implicit class DeviceToPeroperty(x: Device) { + def asProperty: Seq[ResourceValue] = Seq(ResourceReference(x.label)) + } + def EnableMonitors[T](body: Parameters => T)(implicit p: Parameters) = body(p.alterPartial { case MonitorsEnabled => true }) diff --git a/src/main/scala/groundtest/Coreplex.scala b/src/main/scala/groundtest/Coreplex.scala index bd3d6a69..ba044c46 100644 --- a/src/main/scala/groundtest/Coreplex.scala +++ b/src/main/scala/groundtest/Coreplex.scala @@ -44,9 +44,9 @@ class GroundTestCoreplexModule[+L <: GroundTestCoreplex](_outer: L) extends Base with HasMasterAXI4MemPortModuleImp { val success = IO(Bool(OUTPUT)) - outer.tiles.zipWithIndex.map { case(t, i) => t.module.io.hartid := UInt(i) } + outer.tiles.zipWithIndex.map { case(t, i) => t.module.constants.hartid := UInt(i) } - val status = DebugCombiner(outer.tiles.map(_.module.io.status)) + val status = DebugCombiner(outer.tiles.map(_.module.status)) success := status.finished } diff --git a/src/main/scala/groundtest/Tile.scala b/src/main/scala/groundtest/Tile.scala index ccb8b853..e38ebb05 100644 --- a/src/main/scala/groundtest/Tile.scala +++ b/src/main/scala/groundtest/Tile.scala @@ -7,8 +7,10 @@ import Chisel._ import freechips.rocketchip.config._ import freechips.rocketchip.diplomacy._ import freechips.rocketchip.coreplex._ +import freechips.rocketchip.interrupts._ import freechips.rocketchip.rocket.{DCache, RocketCoreParams} import freechips.rocketchip.tile._ +import freechips.rocketchip.tilelink._ import scala.collection.mutable.ListBuffer trait GroundTestTileParams extends TileParams { @@ -28,19 +30,21 @@ trait GroundTestTileParams extends TileParams { case object GroundTestTilesKey extends Field[Seq[GroundTestTileParams]] -abstract class GroundTestTile(params: GroundTestTileParams)(implicit p: Parameters) extends BaseTile(params)(p) { - val slave = None +abstract class GroundTestTile(params: GroundTestTileParams) + (implicit p: Parameters) + extends BaseTile(params, crossing = SynchronousCrossing())(p) { + val intInwardNode: IntInwardNode = IntIdentityNode() + val intOutwardNode: IntOutwardNode = IntIdentityNode() + val slaveNode: TLInwardNode = TLIdentityNode() + val dcacheOpt = params.dcache.map { dc => LazyModule(new DCache(0)) } - override lazy val module = new GroundTestTileModule(this, () => new GroundTestTileBundle(this)) + override lazy val module = new GroundTestTileModuleImp(this) } -class GroundTestTileBundle[+L <: GroundTestTile](_outer: L) extends BaseTileBundle(_outer) { - val status = new GroundTestStatus +class GroundTestTileModuleImp(outer: GroundTestTile) extends BaseTileModuleImp(outer) { + val status = IO(new GroundTestStatus) val halt_and_catch_fire = None -} - -class GroundTestTileModule[+L <: GroundTestTile, +B <: GroundTestTileBundle[L]](_outer: L, _io: () => B) extends BaseTileModule(_outer, _io) { outer.dcacheOpt foreach { dcache => val ptw = Module(new DummyPTW(1)) diff --git a/src/main/scala/groundtest/TraceGen.scala b/src/main/scala/groundtest/TraceGen.scala index 13ddd369..496d574b 100644 --- a/src/main/scala/groundtest/TraceGen.scala +++ b/src/main/scala/groundtest/TraceGen.scala @@ -23,6 +23,7 @@ import Chisel._ import freechips.rocketchip.config.{Field, Parameters} import freechips.rocketchip.rocket._ import freechips.rocketchip.tile._ +import freechips.rocketchip.tilelink._ import freechips.rocketchip.util._ import scala.util.Random @@ -65,7 +66,7 @@ case class TraceGenParams( memStart: BigInt, //p(ExtMem).base numGens: Int) extends GroundTestTileParams { def build(i: Int, p: Parameters): GroundTestTile = new TraceGenTile(i, this)(p) - val hartid = 0 + val hartId = 0 val trace = false val blockerCtrlAddr = None } @@ -578,13 +579,14 @@ class TraceGenerator(val params: TraceGenParams)(implicit val p: Parameters) ext // ======================= class TraceGenTile(val id: Int, val params: TraceGenParams)(implicit p: Parameters) extends GroundTestTile(params) { - override lazy val module = new TraceGenTileModule(this) + val masterNode: TLOutwardNode = dcacheOpt.map(_.node).getOrElse(TLIdentityNode()) + override lazy val module = new TraceGenTileModuleImp(this) } -class TraceGenTileModule(outer: TraceGenTile) extends GroundTestTileModule(outer, () => new GroundTestTileBundle(outer)) { +class TraceGenTileModuleImp(outer: TraceGenTile) extends GroundTestTileModuleImp(outer) { val tracegen = Module(new TraceGenerator(outer.params)) - tracegen.io.hartid := io.hartid + tracegen.io.hartid := constants.hartid outer.dcacheOpt foreach { dcache => val dcacheIF = Module(new SimpleHellaCacheIF()) @@ -592,10 +594,10 @@ class TraceGenTileModule(outer: TraceGenTile) extends GroundTestTileModule(outer dcache.module.io.cpu <> dcacheIF.io.cache } - io.status.finished := tracegen.io.finished - io.status.timeout.valid := tracegen.io.timeout - io.status.timeout.bits := UInt(0) - io.status.error.valid := Bool(false) + status.finished := tracegen.io.finished + status.timeout.valid := tracegen.io.timeout + status.timeout.bits := UInt(0) + status.error.valid := Bool(false) assert(!tracegen.io.timeout, s"TraceGen tile ${outer.id}: request timed out") } diff --git a/src/main/scala/rocket/Frontend.scala b/src/main/scala/rocket/Frontend.scala index be8eb3ef..bf053231 100644 --- a/src/main/scala/rocket/Frontend.scala +++ b/src/main/scala/rocket/Frontend.scala @@ -307,19 +307,15 @@ class FrontendModule(outer: Frontend) extends LazyModuleImp(outer) } /** Mix-ins for constructing tiles that have an ICache-based pipeline frontend */ -trait HasICacheFrontend extends CanHavePTW with HasTileLinkMasterPort { +trait HasICacheFrontend extends CanHavePTW { this: BaseTile => val module: HasICacheFrontendModule - val frontend = LazyModule(new Frontend(tileParams.icache.get, hartid: Int)) - val hartid: Int - tileBus.node := frontend.masterNode + val frontend = LazyModule(new Frontend(tileParams.icache.get, hartId)) + tlMasterXbar.node := frontend.masterNode + connectTLSlave(frontend.slaveNode, tileParams.core.fetchBytes) nPTWPorts += 1 } -trait HasICacheFrontendBundle extends HasTileLinkMasterPortBundle { - val outer: HasICacheFrontend -} - -trait HasICacheFrontendModule extends CanHavePTWModule with HasTileLinkMasterPortModule { +trait HasICacheFrontendModule extends CanHavePTWModule { val outer: HasICacheFrontend ptwPorts += outer.frontend.module.io.ptw } diff --git a/src/main/scala/rocket/HellaCache.scala b/src/main/scala/rocket/HellaCache.scala index 4648a4b9..2467a670 100644 --- a/src/main/scala/rocket/HellaCache.scala +++ b/src/main/scala/rocket/HellaCache.scala @@ -194,27 +194,21 @@ class HellaCacheModule(outer: HellaCache) extends LazyModuleImp(outer) /** Mix-ins for constructing tiles that have a HellaCache */ -trait HasHellaCache extends HasTileLinkMasterPort with HasTileParameters { +trait HasHellaCache { this: BaseTile => val module: HasHellaCacheModule implicit val p: Parameters def findScratchpadFromICache: Option[AddressSet] - val hartid: Int var nDCachePorts = 0 val dcache: HellaCache = LazyModule( if(tileParams.dcache.get.nMSHRs == 0) { - new DCache(hartid, findScratchpadFromICache _, p(RocketCrossingKey).head.knownRatio) - } else { new NonBlockingDCache(hartid) }) + new DCache(hartId, findScratchpadFromICache _, p(RocketCrossingKey).head.knownRatio) + } else { new NonBlockingDCache(hartId) }) - tileBus.node := dcache.node + tlMasterXbar.node := dcache.node } -trait HasHellaCacheBundle extends HasTileLinkMasterPortBundle { +trait HasHellaCacheModule { val outer: HasHellaCache -} - -trait HasHellaCacheModule extends HasTileLinkMasterPortModule { - val outer: HasHellaCache - //val io: HasHellaCacheBundle val dcachePorts = ListBuffer[HellaCacheIO]() val dcacheArb = Module(new HellaCacheArbiter(outer.nDCachePorts)(outer.p)) outer.dcache.module.io.cpu <> dcacheArb.io.mem diff --git a/src/main/scala/rocket/ICache.scala b/src/main/scala/rocket/ICache.scala index b3465788..abb68428 100644 --- a/src/main/scala/rocket/ICache.scala +++ b/src/main/scala/rocket/ICache.scala @@ -45,11 +45,11 @@ class ICacheErrors(implicit p: Parameters) extends CoreBundle()(p) val uncorrectable = (cacheParams.itimAddr.nonEmpty && cacheParams.dataECC.canDetect).option(Valid(UInt(width = paddrBits))) } -class ICache(val icacheParams: ICacheParams, val hartid: Int)(implicit p: Parameters) extends LazyModule { +class ICache(val icacheParams: ICacheParams, val hartId: Int)(implicit p: Parameters) extends LazyModule { lazy val module = new ICacheModule(this) val masterNode = TLClientNode(Seq(TLClientPortParameters(Seq(TLClientParameters( sourceId = IdRange(0, 1 + icacheParams.prefetch.toInt), // 0=refill, 1=hint - name = s"Core ${hartid} ICache"))))) + name = s"Core ${hartId} ICache"))))) val size = icacheParams.nSets * icacheParams.nWays * icacheParams.blockBytes val device = new SimpleDevice("itim", Seq("sifive,itim0")) @@ -100,7 +100,7 @@ class ICacheBundle(outer: ICache) extends CoreBundle()(outer.p) { // get a tile-specific property without breaking deduplication object GetPropertyByHartId { def apply[T <: Data](tiles: Seq[RocketTileParams], f: RocketTileParams => Option[T], hartId: UInt): T = { - PriorityMux(tiles.collect { case t if f(t).isDefined => (t.hartid === hartId) -> f(t).get }) + PriorityMux(tiles.collect { case t if f(t).isDefined => (t.hartId === hartId) -> f(t).get }) } } diff --git a/src/main/scala/rocket/PTW.scala b/src/main/scala/rocket/PTW.scala index 47192482..adc2ba32 100644 --- a/src/main/scala/rocket/PTW.scala +++ b/src/main/scala/rocket/PTW.scala @@ -287,8 +287,7 @@ class PTW(n: Int)(implicit edge: TLEdgeOut, p: Parameters) extends CoreModule()( } /** Mix-ins for constructing tiles that might have a PTW */ -trait CanHavePTW extends HasHellaCache { - implicit val p: Parameters +trait CanHavePTW extends HasTileParameters with HasHellaCache { this: BaseTile => val module: CanHavePTWModule var nPTWPorts = 1 nDCachePorts += usingPTW.toInt diff --git a/src/main/scala/rocket/ScratchpadSlavePort.scala b/src/main/scala/rocket/ScratchpadSlavePort.scala index 7951d7f2..5989c6bc 100644 --- a/src/main/scala/rocket/ScratchpadSlavePort.scala +++ b/src/main/scala/rocket/ScratchpadSlavePort.scala @@ -6,14 +6,12 @@ import Chisel._ import Chisel.ImplicitConversions._ import freechips.rocketchip.config.Parameters -import freechips.rocketchip.coreplex.{CacheBlockBytes, SystemBusKey} -import freechips.rocketchip.devices.tilelink._ import freechips.rocketchip.diplomacy._ import freechips.rocketchip.tile._ import freechips.rocketchip.tilelink._ -import freechips.rocketchip.interrupts._ import freechips.rocketchip.util._ +/* This adapter converts between diplomatic TileLink and non-diplomatic HellaCacheIO */ class ScratchpadSlavePort(address: AddressSet, coreDataBytes: Int, usingAtomics: Boolean)(implicit p: Parameters) extends LazyModule { val device = new SimpleDevice("dtim", Seq("sifive,dtim0")) val node = TLManagerNode(Seq(TLManagerPortParameters( @@ -94,72 +92,3 @@ class ScratchpadSlavePort(address: AddressSet, coreDataBytes: Int, usingAtomics: tl_in.e.ready := Bool(true) } } - -/** Mix-ins for constructing tiles that have optional scratchpads */ -trait CanHaveScratchpad extends HasHellaCache with HasICacheFrontend { - val module: CanHaveScratchpadModule - val cacheBlockBytes = p(CacheBlockBytes) - val masterPortBeatBytes = p(SystemBusKey).beatBytes - - val scratch = tileParams.dcache.flatMap { d => d.scratch.map(s => - LazyModule(new ScratchpadSlavePort(AddressSet(s, d.dataScratchpadBytes-1), xBytes, tileParams.core.useAtomics && !tileParams.core.useAtomicsOnlyForIO))) - } - - val intOutputNode = tileParams.core.tileControlAddr.map(dummy => IntIdentityNode()) - val busErrorUnit = tileParams.core.tileControlAddr map { a => - val beu = LazyModule(new BusErrorUnit(new L1BusErrors, BusErrorUnitParams(a))) - intOutputNode.get := beu.intNode - beu - } - - val tile_master_blocker = - tileParams.blockerCtrlAddr - .map(BasicBusBlockerParams(_, xBytes, masterPortBeatBytes, deadlock = true)) - .map(bp => LazyModule(new BasicBusBlocker(bp))) - - masterNode := tile_master_blocker.map { _.node := tileBus.node } getOrElse { tileBus.node } - - // connect any combination of ITIM, DTIM, and BusErrorUnit - val slaveNode = TLIdentityNode() - DisableMonitors { implicit p => - val xbarPorts = - scratch.map(lm => (lm.node, xBytes)) ++ - busErrorUnit.map(lm => (lm.node, xBytes)) ++ - tileParams.icache.flatMap(icache => icache.itimAddr.map(a => (frontend.slaveNode, tileParams.core.fetchBytes))) ++ - tile_master_blocker.map( lm => (lm.controlNode, xBytes)) - - if (xbarPorts.nonEmpty) { - val xbar = LazyModule(new TLXbar) - xbar.node := slaveNode - xbarPorts.foreach { case (port, bytes) => - (Seq(port, TLFragmenter(bytes, cacheBlockBytes, earlyAck=EarlyAck.PutFulls)) - ++ (xBytes != bytes).option(TLWidthWidget(xBytes))) - .foldRight(xbar.node:TLOutwardNode)(_ := _) - } - } - } - - def findScratchpadFromICache: Option[AddressSet] = scratch.map { s => - val finalNode = frontend.masterNode.edges.out.head.manager.managers.find(_.nodePath.last == s.node) - require (finalNode.isDefined, "Could not find the scratch pad; not reachable via icache?") - require (finalNode.get.address.size == 1, "Scratchpad address space was fragmented!") - finalNode.get.address(0) - } - - nDCachePorts += (scratch.isDefined).toInt -} - -trait CanHaveScratchpadBundle extends HasHellaCacheBundle with HasICacheFrontendBundle { - val outer: CanHaveScratchpad -} - -trait CanHaveScratchpadModule extends HasHellaCacheModule with HasICacheFrontendModule { - val outer: CanHaveScratchpad - val io: CanHaveScratchpadBundle - - outer.scratch.foreach { lm => dcachePorts += lm.module.io.dmem } - outer.busErrorUnit.foreach { lm => - lm.module.io.errors.dcache := outer.dcache.module.io.errors - lm.module.io.errors.icache := outer.frontend.module.io.errors - } -} diff --git a/src/main/scala/tile/BaseTile.scala b/src/main/scala/tile/BaseTile.scala index dfa84a58..c8c669a2 100644 --- a/src/main/scala/tile/BaseTile.scala +++ b/src/main/scala/tile/BaseTile.scala @@ -5,7 +5,9 @@ package freechips.rocketchip.tile import Chisel._ import freechips.rocketchip.config._ +import freechips.rocketchip.coreplex._ import freechips.rocketchip.diplomacy._ +import freechips.rocketchip.interrupts._ import freechips.rocketchip.rocket._ import freechips.rocketchip.tilelink._ import freechips.rocketchip.util._ @@ -22,7 +24,7 @@ trait TileParams { val rocc: Seq[RoCCParams] val btb: Option[BTBParams] val trace: Boolean - val hartid: Int + val hartId: Int val blockerCtrlAddr: Option[BigInt] } @@ -62,66 +64,131 @@ trait HasTileParameters { def vaddrBitsExtended: Int = vpnBitsExtended + pgIdxBits def maxPAddrBits: Int = xLen match { case 32 => 34; case 64 => 56 } + def hartId: Int = tileParams.hartId def hartIdLen: Int = p(MaxHartIdBits) def resetVectorLen: Int = paddrBits + def cacheBlockBytes = p(CacheBlockBytes) + def lgCacheBlockBytes = log2Up(cacheBlockBytes) + def masterPortBeatBytes = p(SystemBusKey).beatBytes + def dcacheArbPorts = 1 + usingVM.toInt + usingDataScratchpad.toInt + tileParams.rocc.size + + // TODO merge with isaString in CSR.scala + def isaDTS: String = { + val m = if (tileParams.core.mulDiv.nonEmpty) "m" else "" + val a = if (tileParams.core.useAtomics) "a" else "" + val f = if (tileParams.core.fpu.nonEmpty) "f" else "" + val d = if (tileParams.core.fpu.nonEmpty && p(XLen) > 32) "d" else "" + val c = if (tileParams.core.useCompressed) "c" else "" + s"rv${p(XLen)}i$m$a$f$d$c" + } + + def tileProperties: PropertyMap = { + val dcache = tileParams.dcache.filter(!_.scratch.isDefined).map(d => Map( + "d-cache-block-size" -> cacheBlockBytes.asProperty, + "d-cache-sets" -> d.nSets.asProperty, + "d-cache-size" -> (d.nSets * d.nWays * cacheBlockBytes).asProperty) + ).getOrElse(Nil) + + val incoherent = if (!tileParams.core.useAtomicsOnlyForIO) Nil else Map( + "sifive,d-cache-incoherent" -> Nil) + + val icache = tileParams.icache.map(i => Map( + "i-cache-block-size" -> cacheBlockBytes.asProperty, + "i-cache-sets" -> i.nSets.asProperty, + "i-cache-size" -> (i.nSets * i.nWays * cacheBlockBytes).asProperty) + ).getOrElse(Nil) + + val dtlb = tileParams.dcache.filter(_ => tileParams.core.useVM).map(d => Map( + "d-tlb-size" -> d.nTLBEntries.asProperty, + "d-tlb-sets" -> 1.asProperty)).getOrElse(Nil) + + val itlb = tileParams.icache.filter(_ => tileParams.core.useVM).map(i => Map( + "i-tlb-size" -> i.nTLBEntries.asProperty, + "i-tlb-sets" -> 1.asProperty)).getOrElse(Nil) + + val mmu = if (!tileParams.core.useVM) Nil else Map( + "tlb-split" -> Nil, + "mmu-type" -> (p(PgLevels) match { + case 2 => "riscv,sv32" + case 3 => "riscv,sv39" + case 4 => "riscv,sv48" + }).asProperty) + + dcache ++ icache ++ dtlb ++ itlb ++ mmu ++ incoherent + } + } -abstract class BareTile(implicit p: Parameters) extends LazyModule +/** Base class for all Tiles that use TileLink */ +abstract class BaseTile(tileParams: TileParams, val crossing: CoreplexClockCrossing) + (implicit p: Parameters) extends LazyModule with HasTileParameters with HasCrossing +{ + def module: BaseTileModuleImp[BaseTile] + def masterNode: TLOutwardNode + def slaveNode: TLInwardNode + def intInwardNode: IntInwardNode + def intOutwardNode: IntOutwardNode -abstract class BareTileBundle[+L <: BareTile](_outer: L) extends GenericParameterizedBundle(_outer) { - val outer = _outer - implicit val p = outer.p + protected val tlOtherMastersNode = TLIdentityNode() + protected val tlMasterXbar = LazyModule(new TLXbar) + protected val tlSlaveXbar = LazyModule(new TLXbar) + protected val intXbar = LazyModule(new IntXbar) + protected val intSinkNode = IntSinkNode(IntSinkPortSimple()) + + def connectTLSlave(node: TLNode, bytes: Int) { + DisableMonitors { implicit p => + (Seq(node, TLFragmenter(bytes, cacheBlockBytes, earlyAck=EarlyAck.PutFulls)) + ++ (xBytes != bytes).option(TLWidthWidget(xBytes))) + .foldRight(tlSlaveXbar.node:TLOutwardNode)(_ :*= _) + } + } + + // Find resource labels for all the outward caches + def nextLevelCacheProperty: PropertyOption = { + val outer = tlMasterXbar.node.edges.out + .flatMap(_.manager.managers) + .filter(_.supportsAcquireB) + .flatMap(_.resources.headOption) + .map(_.owner.label) + .distinct + if (outer.isEmpty) None + else Some("next-level-cache" -> outer.map(l => ResourceReference(l)).toList) + } + + def toDescription(resources: ResourceBindings)(compat: String, extraProperties: PropertyMap = Nil): Description = { + val cpuProperties: PropertyMap = Map( + "reg" -> resources("reg").map(_.value), + "device_type" -> "cpu".asProperty, + "compatible" -> Seq(ResourceString(compat), ResourceString("riscv")), + "status" -> "okay".asProperty, + "clock-frequency" -> tileParams.core.bootFreqHz.asProperty, + "riscv,isa" -> isaDTS.asProperty, + "timebase-frequency" -> p(DTSTimebase).asProperty) + + Description(s"cpus/cpu@${hartId}", (cpuProperties ++ nextLevelCacheProperty ++ tileProperties ++ extraProperties).toMap) + } } -abstract class BareTileModule[+L <: BareTile, +B <: BareTileBundle[L]](_outer: L, _io: () => B) extends LazyModuleImp(_outer) { - val outer = _outer - val io = IO(_io ()) +class BaseTileModuleImp[+L <: BaseTile](val outer: L) extends LazyModuleImp(outer) with HasTileParameters { + + require(xLen == 32 || xLen == 64) + require(paddrBits <= maxPAddrBits) + require(resetVectorLen <= xLen) + require(resetVectorLen <= vaddrBitsExtended) + require (log2Up(hartId + 1) <= hartIdLen, s"p(MaxHartIdBits) of $hartIdLen is not enough for hartid $hartId") + + val trace = tileParams.trace.option(IO(Vec(tileParams.core.retireWidth, new TracedInstruction).asOutput)) + val constants = IO(new TileInputConstants) + + val fpuOpt = outer.tileParams.core.fpu.map(params => Module(new FPU(params)(outer.p))) } -/** Uses TileLink master port to connect caches and accelerators to the coreplex */ -trait HasTileLinkMasterPort { - implicit val p: Parameters - val module: HasTileLinkMasterPortModule - val masterNode = TLIdentityNode() - val tileBus = LazyModule(new TLXbar) // TileBus xbar for cache backends to connect to -} - -trait HasTileLinkMasterPortBundle { - val outer: HasTileLinkMasterPort -} - -trait HasTileLinkMasterPortModule { - val outer: HasTileLinkMasterPort - val io: HasTileLinkMasterPortBundle -} - -/** Some other standard inputs */ +/** Some other non-tilelink but still standard inputs */ trait HasExternallyDrivenTileConstants extends Bundle with HasTileParameters { val hartid = UInt(INPUT, hartIdLen) val reset_vector = UInt(INPUT, resetVectorLen) } -trait CanHaveInstructionTracePort extends Bundle with HasTileParameters { - val trace = tileParams.trace.option(Vec(tileParams.core.retireWidth, new TracedInstruction).asOutput) -} - -/** Base class for all Tiles that use TileLink */ -abstract class BaseTile(tileParams: TileParams)(implicit p: Parameters) extends BareTile - with HasTileParameters { - def module: BaseTileModule[BaseTile, BaseTileBundle[BaseTile]] -} - -abstract class BaseTileBundle[+L <: BaseTile](_outer: L) extends BareTileBundle(_outer) - with HasExternallyDrivenTileConstants - with CanHaveInstructionTracePort - with CanHaltAndCatchFire - -class BaseTileModule[+L <: BaseTile, +B <: BaseTileBundle[L]](_outer: L, _io: () => B) extends BareTileModule(_outer, _io) - with HasTileParameters { - require(xLen == 32 || xLen == 64) - require(paddrBits <= maxPAddrBits) - require(resetVectorLen <= xLen) - require(resetVectorLen <= vaddrBitsExtended) -} +class TileInputConstants(implicit val p: Parameters) extends ParameterizedBundle with HasExternallyDrivenTileConstants diff --git a/src/main/scala/tile/Core.scala b/src/main/scala/tile/Core.scala index b58d31c2..12d2a83f 100644 --- a/src/main/scala/tile/Core.scala +++ b/src/main/scala/tile/Core.scala @@ -13,6 +13,7 @@ case object XLen extends Field[Int] // These parameters can be varied per-core trait CoreParams { + val bootFreqHz: BigInt val useVM: Boolean val useUser: Boolean val useDebug: Boolean diff --git a/src/main/scala/tile/FPU.scala b/src/main/scala/tile/FPU.scala index f64fbd2c..77f8c509 100644 --- a/src/main/scala/tile/FPU.scala +++ b/src/main/scala/tile/FPU.scala @@ -874,12 +874,3 @@ class FPU(cfg: FPUParams)(implicit p: Parameters) extends FPUModule()(p) { req } } - -/** Mix-ins for constructing tiles that may have an FPU external to the core pipeline */ -trait CanHaveSharedFPU extends HasTileParameters - -trait CanHaveSharedFPUModule { - val outer: CanHaveSharedFPU - val fpuOpt = outer.tileParams.core.fpu.map(params => Module(new FPU(params)(outer.p))) - // TODO fpArb could go here instead of inside LegacyRoccComplex -} diff --git a/src/main/scala/tile/Interrupts.scala b/src/main/scala/tile/Interrupts.scala index 0043089d..13c5d64e 100644 --- a/src/main/scala/tile/Interrupts.scala +++ b/src/main/scala/tile/Interrupts.scala @@ -5,7 +5,8 @@ package freechips.rocketchip.tile import Chisel._ import freechips.rocketchip.config.Parameters -import freechips.rocketchip.interrupts.{IntSinkNode, IntSinkPortSimple} +import freechips.rocketchip.diplomacy._ +import freechips.rocketchip.interrupts._ import freechips.rocketchip.util._ class TileInterrupts(implicit p: Parameters) extends CoreBundle()(p) { @@ -18,11 +19,33 @@ class TileInterrupts(implicit p: Parameters) extends CoreBundle()(p) { } // Use diplomatic interrupts to external interrupts from the coreplex into the tile -trait HasExternalInterrupts extends HasTileParameters { - implicit val p: Parameters - val module: HasExternalInterruptsModule +trait HasExternalInterrupts { this: BaseTile => - val intNode = IntSinkNode(IntSinkPortSimple()) + val intInwardNode = intXbar.intnode + intSinkNode := intXbar.intnode + + val intcDevice = new Device { + def describe(resources: ResourceBindings): Description = { + Description(s"cpus/cpu@$hartId/interrupt-controller", Map( + "compatible" -> "riscv,cpu-intc".asProperty, + "interrupt-controller" -> Nil, + "#interrupt-cells" -> 1.asProperty)) + } + } + + ResourceBinding { + Resource(intcDevice, "reg").bind(ResourceInt(BigInt(hartId))) + + intSinkNode.edges.in.flatMap(_.source.sources).map { case s => + for (i <- s.range.start until s.range.end) { + csrIntMap.lift(i).foreach { j => + s.resources.foreach { r => + r.bind(intcDevice, ResourceInt(j)) + } + } + } + } + } // TODO: the order of the following two functions must match, and // also match the order which things are connected to the @@ -34,15 +57,6 @@ trait HasExternalInterrupts extends HasTileParameters { val seip = if (usingVM) Seq(9) else Nil List(65535, 3, 7, 11) ++ seip ++ List.tabulate(nlips)(_ + 16) } -} - -trait HasExternalInterruptsBundle { - val outer: HasExternalInterrupts -} - -trait HasExternalInterruptsModule { - val outer: HasExternalInterrupts - val io: HasExternalInterruptsBundle // go from flat diplomatic Interrupts to bundled TileInterrupts def decodeCoreInterrupts(core: TileInterrupts) { @@ -56,7 +70,7 @@ trait HasExternalInterruptsModule { val core_ips = core.lip - val (interrupts, _) = outer.intNode.in(0) + val (interrupts, _) = intSinkNode.in(0) (async_ips ++ periph_ips ++ seip ++ core_ips).zip(interrupts).foreach { case(c, i) => c := i } } } diff --git a/src/main/scala/tile/L1Cache.scala b/src/main/scala/tile/L1Cache.scala index 8101ec2d..811a9773 100644 --- a/src/main/scala/tile/L1Cache.scala +++ b/src/main/scala/tile/L1Cache.scala @@ -14,16 +14,13 @@ trait L1CacheParams { def nWays: Int def rowBits: Int def nTLBEntries: Int - def blockBytes: Int + def blockBytes: Int // TODO this is ignored in favor of p(CacheBlockBytes) in BaseTile } -trait HasL1CacheParameters { - implicit val p: Parameters +trait HasL1CacheParameters extends HasTileParameters { val cacheParams: L1CacheParams private val bundleParams = p(SharedMemoryTLEdge).bundle - def cacheBlockBytes = cacheParams.blockBytes - def lgCacheBlockBytes = log2Up(cacheBlockBytes) def nSets = cacheParams.nSets def blockOffBits = lgCacheBlockBytes def idxBits = log2Up(cacheParams.nSets) diff --git a/src/main/scala/tile/LazyRoCC.scala b/src/main/scala/tile/LazyRoCC.scala index cbbb175b..49dff340 100644 --- a/src/main/scala/tile/LazyRoCC.scala +++ b/src/main/scala/tile/LazyRoCC.scala @@ -77,27 +77,22 @@ class LazyRoCCModule(outer: LazyRoCC) extends LazyModuleImp(outer) { /** Mixins for including RoCC **/ -trait HasLazyRoCC extends CanHaveSharedFPU with CanHavePTW with HasTileLinkMasterPort { - implicit val p: Parameters - val module: HasLazyRoCCModule - +trait HasLazyRoCC extends CanHavePTW { this: BaseTile => val roccs = p(BuildRoCC).zipWithIndex.map { case (accelParams, i) => accelParams.generator(p.alterPartial({ case RoccNPTWPorts => accelParams.nPTWPorts }))} - roccs.map(_.atlNode).foreach { atl => tileBus.node :=* atl } - roccs.map(_.tlNode).foreach { tl => masterNode :=* tl } + roccs.map(_.atlNode).foreach { atl => tlMasterXbar.node :=* atl } + roccs.map(_.tlNode).foreach { tl => tlOtherMastersNode :=* tl } nPTWPorts += p(BuildRoCC).map(_.nPTWPorts).foldLeft(0)(_ + _) nDCachePorts += roccs.size } -trait HasLazyRoCCModule extends CanHaveSharedFPUModule - with CanHavePTWModule - with HasCoreParameters - with HasTileLinkMasterPortModule { - val outer: HasLazyRoCC +trait HasLazyRoCCModule[+L <: BaseTile with HasLazyRoCC] extends CanHavePTWModule + with HasCoreParameters { this: BaseTileModuleImp[L] => + val roccCore = Wire(new RoCCCoreIO()(outer.p)) val buildRocc = outer.p(BuildRoCC) diff --git a/src/main/scala/tile/RocketTile.scala b/src/main/scala/tile/RocketTile.scala index 432fc3af..e2126ebe 100644 --- a/src/main/scala/tile/RocketTile.scala +++ b/src/main/scala/tile/RocketTile.scala @@ -5,11 +5,12 @@ package freechips.rocketchip.tile import Chisel._ import freechips.rocketchip.config._ -import freechips.rocketchip.coreplex._ +import freechips.rocketchip.coreplex.CoreplexClockCrossing +import freechips.rocketchip.devices.tilelink._ import freechips.rocketchip.diplomacy._ -import freechips.rocketchip.rocket._ -import freechips.rocketchip.tilelink._ import freechips.rocketchip.interrupts._ +import freechips.rocketchip.tilelink._ +import freechips.rocketchip.rocket._ import freechips.rocketchip.util._ case class RocketTileParams( @@ -22,7 +23,7 @@ case class RocketTileParams( trace: Boolean = false, hcfOnUncorrectable: Boolean = false, name: Option[String] = Some("tile"), - hartid: Int = 0, + hartId: Int = 0, blockerCtrlAddr: Option[BigInt] = None, boundaryBuffers: Boolean = false // if synthesized with hierarchical PnR, cut feed-throughs? ) extends TileParams { @@ -30,138 +31,96 @@ case class RocketTileParams( require(dcache.isDefined) } -abstract class HartedTile(tileParams: TileParams, val hartid: Int)(implicit p: Parameters) extends BaseTile(tileParams)(p) { - require (log2Up(hartid + 1) <= p(MaxHartIdBits), s"p(MaxHartIdBits) of ${p(MaxHartIdBits)} is not enough for hartid ${hartid}") -} - -class RocketTile(val rocketParams: RocketTileParams)(implicit p: Parameters) extends HartedTile(rocketParams, rocketParams.hartid)(p) +class RocketTile( + val rocketParams: RocketTileParams, + crossing: CoreplexClockCrossing) + (implicit p: Parameters) extends BaseTile(rocketParams, crossing)(p) with HasExternalInterrupts with HasLazyRoCC // implies CanHaveSharedFPU with CanHavePTW with HasHellaCache - with CanHaveScratchpad { // implies CanHavePTW with HasHellaCache with HasICacheFrontend + with HasHellaCache + with HasICacheFrontend { - nDCachePorts += 1 // core TODO dcachePorts += () => module.core.io.dmem ?? + val intOutwardNode = IntIdentityNode() + val slaveNode = TLIdentityNode() + val masterNode = TLIdentityNode() - private def ofInt(x: Int) = Seq(ResourceInt(BigInt(x))) - private def ofStr(x: String) = Seq(ResourceString(x)) - private def ofRef(x: Device) = Seq(ResourceReference(x.label)) + val dtim_adapter = tileParams.dcache.flatMap { d => d.scratch.map(s => + LazyModule(new ScratchpadSlavePort(AddressSet(s, d.dataScratchpadBytes-1), xBytes, tileParams.core.useAtomics && !tileParams.core.useAtomicsOnlyForIO))) + } + dtim_adapter.foreach(lm => connectTLSlave(lm.node, xBytes)) + + val bus_error_unit = tileParams.core.tileControlAddr map { a => + val beu = LazyModule(new BusErrorUnit(new L1BusErrors, BusErrorUnitParams(a))) + intOutwardNode := beu.intNode + connectTLSlave(beu.node, xBytes) + beu + } + + val tile_master_blocker = + tileParams.blockerCtrlAddr + .map(BasicBusBlockerParams(_, xBytes, masterPortBeatBytes, deadlock = true)) + .map(bp => LazyModule(new BasicBusBlocker(bp))) + + tile_master_blocker.foreach(lm => connectTLSlave(lm.controlNode, xBytes)) + + // TODO: this doesn't block other masters, e.g. RoCCs + tlOtherMastersNode := tile_master_blocker.map { _.node := tlMasterXbar.node } getOrElse { tlMasterXbar.node } + masterNode :=* tlOtherMastersNode + tlSlaveXbar.node :*= slaveNode + + def findScratchpadFromICache: Option[AddressSet] = dtim_adapter.map { s => + val finalNode = frontend.masterNode.edges.out.head.manager.managers.find(_.nodePath.last == s.node) + require (finalNode.isDefined, "Could not find the scratch pad; not reachable via icache?") + require (finalNode.get.address.size == 1, "Scratchpad address space was fragmented!") + finalNode.get.address(0) + } + + nDCachePorts += 1 /*core */ + (dtim_adapter.isDefined).toInt + + val dtimProperty = dtim_adapter.map(d => Map( + "sifive,dtim" -> d.device.asProperty)).getOrElse(Nil) + + val itimProperty = tileParams.icache.flatMap(_.itimAddr.map(i => Map( + "sifive,itim" -> frontend.icache.device.asProperty))).getOrElse(Nil) val cpuDevice = new Device { - def describe(resources: ResourceBindings): Description = { - val block = p(CacheBlockBytes) - val m = if (rocketParams.core.mulDiv.nonEmpty) "m" else "" - val a = if (rocketParams.core.useAtomics) "a" else "" - val f = if (rocketParams.core.fpu.nonEmpty) "f" else "" - val d = if (rocketParams.core.fpu.nonEmpty && p(XLen) > 32) "d" else "" - val c = if (rocketParams.core.useCompressed) "c" else "" - val isa = s"rv${p(XLen)}i$m$a$f$d$c" - - val dcache = rocketParams.dcache.filter(!_.scratch.isDefined).map(d => Map( - "d-cache-block-size" -> ofInt(block), - "d-cache-sets" -> ofInt(d.nSets), - "d-cache-size" -> ofInt(d.nSets * d.nWays * block))).getOrElse(Map()) - - val dtim = scratch.map(d => Map( - "sifive,dtim" -> ofRef(d.device))).getOrElse(Map()) - - val itim = if (frontend.icache.slaveNode.edges.in.isEmpty) Map() else Map( - "sifive,itim" -> ofRef(frontend.icache.device)) - - val incoherent = if (!rocketParams.core.useAtomicsOnlyForIO) Map() else Map( - "sifive,d-cache-incoherent" -> Nil) - - val icache = rocketParams.icache.map(i => Map( - "i-cache-block-size" -> ofInt(block), - "i-cache-sets" -> ofInt(i.nSets), - "i-cache-size" -> ofInt(i.nSets * i.nWays * block))).getOrElse(Map()) - - val dtlb = rocketParams.dcache.filter(_ => rocketParams.core.useVM).map(d => Map( - "d-tlb-size" -> ofInt(d.nTLBEntries), - "d-tlb-sets" -> ofInt(1))).getOrElse(Map()) - - val itlb = rocketParams.icache.filter(_ => rocketParams.core.useVM).map(i => Map( - "i-tlb-size" -> ofInt(i.nTLBEntries), - "i-tlb-sets" -> ofInt(1))).getOrElse(Map()) - - val mmu = if (!rocketParams.core.useVM) Map() else Map( - "tlb-split" -> Nil, - "mmu-type" -> ofStr(p(PgLevels) match { - case 2 => "riscv,sv32" - case 3 => "riscv,sv39" - case 4 => "riscv,sv48" - })) - - // Find all the caches - val outer = masterNode.edges.out - .flatMap(_.manager.managers) - .filter(_.supportsAcquireB) - .flatMap(_.resources.headOption) - .map(_.owner.label) - .distinct - val nextlevel: Option[(String, Seq[ResourceValue])] = - if (outer.isEmpty) None else - Some("next-level-cache" -> outer.map(l => ResourceReference(l)).toList) - - Description(s"cpus/cpu@${hartid}", Map( - "reg" -> resources("reg").map(_.value), - "device_type" -> ofStr("cpu"), - "compatible" -> Seq(ResourceString("sifive,rocket0"), ResourceString("riscv")), - "status" -> ofStr("okay"), - "clock-frequency" -> Seq(ResourceInt(rocketParams.core.bootFreqHz)), - "riscv,isa" -> ofStr(isa), - "timebase-frequency" -> Seq(ResourceInt(p(DTSTimebase)))) ++ dcache ++ icache ++ nextlevel ++ mmu ++ itlb ++ dtlb ++ dtim ++ itim ++ incoherent) - } - } - val intcDevice = new Device { - def describe(resources: ResourceBindings): Description = { - Description(s"cpus/cpu@${hartid}/interrupt-controller", Map( - "compatible" -> ofStr("riscv,cpu-intc"), - "interrupt-controller" -> Nil, - "#interrupt-cells" -> ofInt(1))) - } + def describe(resources: ResourceBindings): Description = + toDescription(resources)("sifive,rocket0", dtimProperty ++ itimProperty) } ResourceBinding { - Resource(cpuDevice, "reg").bind(ResourceInt(BigInt(hartid))) - Resource(intcDevice, "reg").bind(ResourceInt(BigInt(hartid))) - - intNode.edges.in.flatMap(_.source.sources).map { case s => - for (i <- s.range.start until s.range.end) { - csrIntMap.lift(i).foreach { j => - s.resources.foreach { r => - r.bind(intcDevice, ResourceInt(j)) - } - } - } - } + Resource(cpuDevice, "reg").bind(ResourceInt(BigInt(hartId))) } - override lazy val module = new RocketTileModule(this) + override lazy val module = new RocketTileModuleImp(this) } -class RocketTileBundle(outer: RocketTile) extends BaseTileBundle(outer) - with HasExternalInterruptsBundle - with CanHaveScratchpadBundle - with CanHaltAndCatchFire { - val halt_and_catch_fire = outer.rocketParams.hcfOnUncorrectable.option(Bool(OUTPUT)) -} - -class RocketTileModule(outer: RocketTile) extends BaseTileModule(outer, () => new RocketTileBundle(outer)) - with HasExternalInterruptsModule - with HasLazyRoCCModule - with CanHaveScratchpadModule { +class RocketTileModuleImp(outer: RocketTile) extends BaseTileModuleImp(outer) + with HasLazyRoCCModule[RocketTile] + with HasHellaCacheModule + with HasICacheFrontendModule { val core = Module(p(BuildCore)(outer.p)) - val uncorrectable = RegInit(Bool(false)) - decodeCoreInterrupts(core.io.interrupts) // Decode the interrupt vector - outer.busErrorUnit.foreach { beu => core.io.interrupts.buserror.get := beu.module.io.interrupt } - core.io.hartid := io.hartid // Pass through the hartid - io.trace.foreach { _ := core.io.trace } - io.halt_and_catch_fire.foreach { _ := uncorrectable } + val uncorrectable = RegInit(Bool(false)) + val halt_and_catch_fire = outer.rocketParams.hcfOnUncorrectable.option(IO(Bool(OUTPUT))) + + outer.dtim_adapter.foreach { lm => dcachePorts += lm.module.io.dmem } + + outer.bus_error_unit.foreach { lm => + lm.module.io.errors.dcache := outer.dcache.module.io.errors + lm.module.io.errors.icache := outer.frontend.module.io.errors + } + + outer.decodeCoreInterrupts(core.io.interrupts) // Decode the interrupt vector + outer.bus_error_unit.foreach { beu => core.io.interrupts.buserror.get := beu.module.io.interrupt } + core.io.hartid := constants.hartid // Pass through the hartid + trace.foreach { _ := core.io.trace } + halt_and_catch_fire.foreach { _ := uncorrectable } outer.frontend.module.io.cpu <> core.io.imem - outer.frontend.module.io.reset_vector := io.reset_vector - outer.frontend.module.io.hartid := io.hartid - outer.dcache.module.io.hartid := io.hartid + outer.frontend.module.io.reset_vector := constants.reset_vector + outer.frontend.module.io.hartid := constants.hartid + outer.dcache.module.io.hartid := constants.hartid dcachePorts += core.io.dmem // TODO outer.dcachePorts += () => module.core.io.dmem ?? fpuOpt foreach { fpu => core.io.fpu <> fpu.io } core.io.ptw <> ptw.io.dpath @@ -188,55 +147,3 @@ class RocketTileModule(outer: RocketTile) extends BaseTileModule(outer, () => ne dcacheArb.io.requestor <> dcachePorts ptw.io.requestor <> ptwPorts } - -class RocketTileWrapperBundle[+L <: RocketTileWrapper](_outer: L) extends BaseTileBundle(_outer) - with CanHaltAndCatchFire { - val halt_and_catch_fire = _outer.rocket.module.io.halt_and_catch_fire.map(_.cloneType) -} - -class RocketTileWrapper( - params: RocketTileParams, - val crossing: CoreplexClockCrossing) - (implicit p: Parameters) extends BaseTile(params) with HasCrossing { - - val rocket = LazyModule(new RocketTile(params)) - - // The buffers needed to cut feed-through paths are microarchitecture specific, so belong here - val masterBuffer = LazyModule(new TLBuffer(BufferParams.none, BufferParams.flow, BufferParams.none, BufferParams.flow, BufferParams(1))) - val masterNode: TLOutwardNode = crossing match { - case _: AsynchronousCrossing => rocket.masterNode - case SynchronousCrossing(b) => - require (!params.boundaryBuffers || (b.depth >= 1 && !b.flow && !b.pipe), "Buffer misconfiguration creates feed-through paths") - rocket.masterNode - case RationalCrossing(dir) => - require (dir != SlowToFast, "Misconfiguration? Core slower than fabric") - if (params.boundaryBuffers) { - masterBuffer.node :=* rocket.masterNode - } else { - rocket.masterNode - } - } - - val slaveBuffer = LazyModule(new TLBuffer(BufferParams.flow, BufferParams.none, BufferParams.none, BufferParams.none, BufferParams.none)) - val slaveNode: TLInwardNode = crossing match { - case _: SynchronousCrossing => rocket.slaveNode // requirement already checked - case _: AsynchronousCrossing => rocket.slaveNode - case _: RationalCrossing => - if (params.boundaryBuffers) { - DisableMonitors { implicit p => rocket.slaveNode :*= slaveBuffer.node } - } else { - rocket.slaveNode - } - } - - val intXbar = LazyModule(new IntXbar) - rocket.intNode := intXbar.intnode - - override lazy val module = new BaseTileModule(this, () => new RocketTileWrapperBundle(this)) { - // signals that do not change based on crossing type: - rocket.module.io.hartid := io.hartid - rocket.module.io.reset_vector := io.reset_vector - io.trace.foreach { _ := rocket.module.io.trace.get } - io.halt_and_catch_fire.foreach { _ := rocket.module.io.halt_and_catch_fire.get } - } -} diff --git a/src/main/scala/tilelink/SRAM.scala b/src/main/scala/tilelink/SRAM.scala index cc664db6..4f151678 100644 --- a/src/main/scala/tilelink/SRAM.scala +++ b/src/main/scala/tilelink/SRAM.scala @@ -20,7 +20,7 @@ class TLRAM( val node = TLManagerNode(Seq(TLManagerPortParameters( Seq(TLManagerParameters( address = List(address) ++ errors, - resources = resources, + resources = device.reg("mem"), regionType = if (cacheable) RegionType.UNCACHED else RegionType.UNCACHEABLE, executable = executable, supportsGet = TransferSizes(1, beatBytes),