2017-07-23 17:31:04 +02:00
|
|
|
// See LICENSE.SiFive for license details.
|
|
|
|
|
2018-01-12 21:29:27 +01:00
|
|
|
package freechips.rocketchip.subsystem
|
2017-07-23 17:31:04 +02:00
|
|
|
|
|
|
|
import Chisel._
|
2017-10-20 04:48:20 +02:00
|
|
|
import chisel3.internal.sourceinfo.SourceInfo
|
2017-07-23 17:31:04 +02:00
|
|
|
import freechips.rocketchip.config.{Field, Parameters}
|
|
|
|
import freechips.rocketchip.devices.tilelink._
|
|
|
|
import freechips.rocketchip.devices.debug.{HasPeripheryDebug, HasPeripheryDebugModuleImp}
|
|
|
|
import freechips.rocketchip.diplomacy._
|
|
|
|
import freechips.rocketchip.tile._
|
|
|
|
import freechips.rocketchip.tilelink._
|
2017-10-20 05:44:54 +02:00
|
|
|
import freechips.rocketchip.interrupts._
|
2017-07-23 17:31:04 +02:00
|
|
|
import freechips.rocketchip.util._
|
|
|
|
|
2017-10-10 08:43:18 +02:00
|
|
|
// TODO: how specific are these to RocketTiles?
|
2018-02-17 00:58:55 +01:00
|
|
|
case class TileMasterPortParams(buffers: Int = 0, cork: Option[Boolean] = None)
|
|
|
|
case class TileSlavePortParams(buffers: Int = 0, blockerCtrlAddr: Option[BigInt] = None)
|
2017-10-10 08:43:18 +02:00
|
|
|
|
|
|
|
case class RocketCrossingParams(
|
2018-01-12 21:29:27 +01:00
|
|
|
crossingType: SubsystemClockCrossing = SynchronousCrossing(),
|
2017-10-11 00:02:50 +02:00
|
|
|
master: TileMasterPortParams = TileMasterPortParams(),
|
2017-10-26 22:52:34 +02:00
|
|
|
slave: TileSlavePortParams = TileSlavePortParams()) {
|
2017-10-10 08:43:18 +02:00
|
|
|
def knownRatio: Option[Int] = crossingType match {
|
|
|
|
case RationalCrossing(_) => Some(2)
|
|
|
|
case _ => None
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-09-09 03:33:44 +02:00
|
|
|
case object RocketTilesKey extends Field[Seq[RocketTileParams]](Nil)
|
2017-10-10 08:43:18 +02:00
|
|
|
case object RocketCrossingKey extends Field[Seq[RocketCrossingParams]](List(RocketCrossingParams()))
|
2017-07-23 17:31:04 +02:00
|
|
|
|
2017-10-06 09:56:23 +02:00
|
|
|
trait HasRocketTiles extends HasTiles
|
2017-07-23 17:31:04 +02:00
|
|
|
with HasPeripheryPLIC
|
2018-01-12 21:29:27 +01:00
|
|
|
with HasPeripheryCLINT
|
2018-02-21 02:10:16 +01:00
|
|
|
with HasPeripheryDebug { this: BaseSubsystem =>
|
2017-07-23 17:31:04 +02:00
|
|
|
val module: HasRocketTilesModuleImp
|
|
|
|
|
2017-12-14 04:00:29 +01:00
|
|
|
protected val rocketTileParams = p(RocketTilesKey)
|
|
|
|
private val NumRocketTiles = rocketTileParams.size
|
2017-10-10 08:43:18 +02:00
|
|
|
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")
|
|
|
|
}
|
2017-12-14 04:00:29 +01:00
|
|
|
private val crossingTuples = rocketTileParams.zip(crossings)
|
2017-07-23 17:31:04 +02:00
|
|
|
|
2017-12-28 23:00:13 +01:00
|
|
|
// Make a tile and wire its nodes into the system,
|
2017-07-23 17:31:04 +02:00
|
|
|
// according to the specified type of clock crossing.
|
2017-12-28 23:00:13 +01:00
|
|
|
// Note that we also inject new nodes into the tile itself,
|
|
|
|
// also based on the crossing type.
|
2017-12-14 04:00:29 +01:00
|
|
|
val rocketTiles = crossingTuples.map { case (tp, crossing) =>
|
2017-10-23 18:39:01 +02:00
|
|
|
// For legacy reasons, it is convenient to store some state
|
|
|
|
// in the global Parameters about the specific tile being built now
|
2017-12-28 23:00:13 +01:00
|
|
|
val rocket = LazyModule(new RocketTile(tp, crossing.crossingType)(p.alterPartial {
|
2017-10-23 18:39:01 +02:00
|
|
|
case TileKey => tp
|
|
|
|
case BuildRoCC => tp.rocc
|
|
|
|
case SharedMemoryTLEdge => sharedMemoryTLEdge
|
|
|
|
})
|
|
|
|
).suggestName(tp.name)
|
|
|
|
|
|
|
|
// Connect the master ports of the tile to the system bus
|
2017-12-28 23:00:13 +01:00
|
|
|
|
|
|
|
def tileMasterBuffering: TLOutwardNode = rocket {
|
|
|
|
// The buffers needed to cut feed-through paths are microarchitecture specific, so belong here
|
2018-02-17 00:58:55 +01:00
|
|
|
val masterBufferNode = TLBuffer(BufferParams.none, BufferParams.flow, BufferParams.none, BufferParams.flow, BufferParams(1))
|
2017-12-28 23:00:13 +01:00
|
|
|
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) {
|
2018-02-17 00:58:55 +01:00
|
|
|
masterBufferNode :=* rocket.masterNode
|
2017-12-28 23:00:13 +01:00
|
|
|
} else {
|
|
|
|
rocket.masterNode
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-02-17 00:58:55 +01:00
|
|
|
sbus.fromTile(tp.name, crossing.master.buffers) {
|
|
|
|
crossing.master.cork
|
|
|
|
.map { u => TLCacheCork(unsafe = u) }
|
|
|
|
.map { _ :=* rocket.crossTLOut }
|
|
|
|
.getOrElse { rocket.crossTLOut }
|
2018-02-15 23:01:49 +01:00
|
|
|
} :=* tileMasterBuffering
|
2017-10-23 18:39:01 +02:00
|
|
|
|
|
|
|
// Connect the slave ports of the tile to the periphery bus
|
2017-12-28 23:00:13 +01:00
|
|
|
|
|
|
|
def tileSlaveBuffering: TLInwardNode = rocket {
|
2018-02-17 00:58:55 +01:00
|
|
|
val slaveBufferNode = TLBuffer(BufferParams.flow, BufferParams.none, BufferParams.none, BufferParams.none, BufferParams.none)
|
2017-12-28 23:00:13 +01:00
|
|
|
crossing.crossingType match {
|
2018-02-17 00:58:55 +01:00
|
|
|
case RationalCrossing(_) if (tp.boundaryBuffers) => rocket.slaveNode :*= slaveBufferNode
|
2018-01-09 03:41:55 +01:00
|
|
|
case _ => rocket.slaveNode
|
2017-12-28 23:00:13 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-02-15 23:01:49 +01:00
|
|
|
DisableMonitors { implicit p =>
|
2018-02-17 00:58:55 +01:00
|
|
|
tileSlaveBuffering :*= pbus.toTile(tp.name) {
|
|
|
|
crossing.slave.blockerCtrlAddr
|
|
|
|
.map { BasicBusBlockerParams(_, pbus.beatBytes, sbus.beatBytes) }
|
|
|
|
.map { bbbp => LazyModule(new BasicBusBlocker(bbbp)) }
|
|
|
|
.map { bbb =>
|
2018-02-21 02:10:16 +01:00
|
|
|
pbus.toVariableWidthSlave(Some("bus_blocker")) { bbb.controlNode }
|
2018-02-17 00:58:55 +01:00
|
|
|
rocket.crossTLIn :*= bbb.node
|
|
|
|
} .getOrElse { rocket.crossTLIn }
|
|
|
|
}
|
2018-02-15 23:01:49 +01:00
|
|
|
}
|
2017-10-23 18:39:01 +02:00
|
|
|
|
|
|
|
// Handle all the different types of interrupts crossing to or from the tile:
|
|
|
|
// 1. Debug interrupt is definitely asynchronous in all cases.
|
|
|
|
// 2. The CLINT and PLIC output interrupts are synchronous to the periphery clock,
|
|
|
|
// so might need to be synchronized depending on the Tile's crossing type.
|
|
|
|
// 3. Local Interrupts are required to already be synchronous to the tile clock.
|
|
|
|
// 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.
|
|
|
|
// NOTE: The order of calls to := matters! They must match how interrupts
|
|
|
|
// are decoded from rocket.intNode inside the tile.
|
|
|
|
|
2017-12-14 04:00:29 +01:00
|
|
|
// 1. always async crossing for debug
|
2017-12-28 23:00:13 +01:00
|
|
|
rocket.intInwardNode := rocket { IntSyncCrossingSink(3) } := debug.intnode
|
2017-10-26 01:13:55 +02:00
|
|
|
|
2017-12-14 04:00:29 +01:00
|
|
|
// 2. clint+plic conditionally crossing
|
2017-12-28 23:00:13 +01:00
|
|
|
val periphIntNode = rocket.intInwardNode :=* rocket.crossIntIn
|
2017-10-26 01:13:55 +02:00
|
|
|
periphIntNode := clint.intnode // msip+mtip
|
|
|
|
periphIntNode := plic.intnode // meip
|
|
|
|
if (tp.core.useVM) periphIntNode := plic.intnode // seip
|
|
|
|
|
2017-12-14 04:00:29 +01:00
|
|
|
// 3. local interrupts never cross
|
2018-01-09 03:41:55 +01:00
|
|
|
// rocket.intInwardNode is wired up externally // lip
|
2017-10-26 01:13:55 +02:00
|
|
|
|
2017-12-14 04:00:29 +01:00
|
|
|
// 4. conditional crossing from core to PLIC
|
2017-12-21 02:18:38 +01:00
|
|
|
FlipRendering { implicit p =>
|
2017-12-28 23:00:13 +01:00
|
|
|
plic.intnode :=* rocket.crossIntOut :=* rocket.intOutwardNode
|
2017-09-27 21:02:04 +02:00
|
|
|
}
|
2017-09-16 03:49:40 +02:00
|
|
|
|
2017-12-28 23:00:13 +01:00
|
|
|
rocket
|
2017-07-23 17:31:04 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-10-08 02:29:50 +02:00
|
|
|
trait HasRocketTilesModuleImp extends HasTilesModuleImp
|
2017-07-23 17:31:04 +02:00
|
|
|
with HasPeripheryDebugModuleImp {
|
2017-10-08 02:29:50 +02:00
|
|
|
val outer: HasRocketTiles
|
2017-07-23 17:31:04 +02:00
|
|
|
}
|
|
|
|
|
2018-01-12 21:29:27 +01:00
|
|
|
class RocketSubsystem(implicit p: Parameters) extends BaseSubsystem
|
2017-07-23 17:31:04 +02:00
|
|
|
with HasRocketTiles {
|
2017-12-14 04:00:29 +01:00
|
|
|
val tiles = rocketTiles
|
2018-02-21 21:51:16 +01:00
|
|
|
override lazy val module = new RocketSubsystemModuleImp(this)
|
2017-07-23 17:31:04 +02:00
|
|
|
}
|
|
|
|
|
2018-02-21 21:51:16 +01:00
|
|
|
class RocketSubsystemModuleImp[+L <: RocketSubsystem](_outer: L) extends BaseSubsystemModuleImp(_outer)
|
2017-12-14 04:00:29 +01:00
|
|
|
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
|
|
|
|
}
|
|
|
|
}
|