2017-07-23 17:31:04 +02:00
|
|
|
// See LICENSE.SiFive for license details.
|
|
|
|
|
|
|
|
package freechips.rocketchip.coreplex
|
|
|
|
|
|
|
|
import Chisel._
|
|
|
|
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._
|
|
|
|
import freechips.rocketchip.util._
|
|
|
|
|
2017-09-09 03:33:44 +02:00
|
|
|
case object RocketTilesKey extends Field[Seq[RocketTileParams]](Nil)
|
|
|
|
case object RocketCrossing extends Field[CoreplexClockCrossing](SynchronousCrossing())
|
2017-07-23 17:31:04 +02:00
|
|
|
|
|
|
|
trait HasRocketTiles extends HasSystemBus
|
|
|
|
with HasPeripheryBus
|
|
|
|
with HasPeripheryPLIC
|
|
|
|
with HasPeripheryClint
|
|
|
|
with HasPeripheryDebug {
|
|
|
|
val module: HasRocketTilesModuleImp
|
|
|
|
|
|
|
|
private val crossing = p(RocketCrossing)
|
|
|
|
private val tileParams = p(RocketTilesKey)
|
|
|
|
val nRocketTiles = tileParams.size
|
2017-10-05 09:31:53 +02:00
|
|
|
val hartIdList = tileParams.map(_.hartid)
|
2017-07-23 17:31:04 +02:00
|
|
|
|
|
|
|
// Handle interrupts to be routed directly into each tile
|
|
|
|
// TODO: figure out how to merge the localIntNodes and coreIntXbar below
|
|
|
|
val localIntCounts = tileParams.map(_.core.nLocalInterrupts)
|
|
|
|
val localIntNodes = tileParams map { t =>
|
|
|
|
(t.core.nLocalInterrupts > 0).option(LazyModule(new IntXbar).intnode)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Make a wrapper for each tile that will wire it to coreplex devices and crossbars,
|
|
|
|
// according to the specified type of clock crossing.
|
2017-10-05 09:31:53 +02:00
|
|
|
val wiringTuple = localIntNodes.zip(tileParams)
|
2017-10-06 07:46:16 +02:00
|
|
|
val rocket_tiles: Seq[BaseTile] = wiringTuple.map { case (lip, tp) =>
|
2017-07-23 17:31:04 +02:00
|
|
|
val pWithExtra = p.alterPartial {
|
2017-08-31 02:57:52 +02:00
|
|
|
case TileKey => tp
|
|
|
|
case BuildRoCC => tp.rocc
|
2017-07-23 17:31:04 +02:00
|
|
|
case SharedMemoryTLEdge => sharedMemoryTLEdge
|
|
|
|
}
|
|
|
|
|
|
|
|
val wrapper = crossing match {
|
|
|
|
case SynchronousCrossing(params) => {
|
2017-10-05 09:31:53 +02:00
|
|
|
val wrapper = LazyModule(new SyncRocketTile(tp)(pWithExtra))
|
2017-09-06 23:40:13 +02:00
|
|
|
sbus.fromSyncTiles(params, tp.externalMasterBuffers, tp.name) :=* wrapper.masterNode
|
2017-09-26 22:23:54 +02:00
|
|
|
FlipRendering { implicit p => wrapper.slaveNode :*= pbus.toSyncSlaves(tp.name, tp.externalSlaveBuffers) }
|
2017-07-23 17:31:04 +02:00
|
|
|
wrapper
|
|
|
|
}
|
|
|
|
case AsynchronousCrossing(depth, sync) => {
|
2017-10-05 09:31:53 +02:00
|
|
|
val wrapper = LazyModule(new AsyncRocketTile(tp)(pWithExtra))
|
2017-09-06 23:40:13 +02:00
|
|
|
sbus.fromAsyncTiles(depth, sync, tp.externalMasterBuffers, tp.name) :=* wrapper.masterNode
|
2017-09-26 22:23:54 +02:00
|
|
|
FlipRendering { implicit p => wrapper.slaveNode :*= pbus.toAsyncSlaves(sync, tp.name, tp.externalSlaveBuffers) }
|
2017-07-23 17:31:04 +02:00
|
|
|
wrapper
|
|
|
|
}
|
|
|
|
case RationalCrossing(direction) => {
|
2017-10-05 09:31:53 +02:00
|
|
|
val wrapper = LazyModule(new RationalRocketTile(tp)(pWithExtra))
|
2017-09-06 23:40:13 +02:00
|
|
|
sbus.fromRationalTiles(direction, tp.externalMasterBuffers, tp.name) :=* wrapper.masterNode
|
2017-09-26 22:23:54 +02:00
|
|
|
FlipRendering { implicit p => wrapper.slaveNode :*= pbus.toRationalSlaves(tp.name, tp.externalSlaveBuffers) }
|
2017-07-23 17:31:04 +02:00
|
|
|
wrapper
|
|
|
|
}
|
|
|
|
}
|
2017-08-31 02:57:52 +02:00
|
|
|
tp.name.foreach(wrapper.suggestName) // Try to stabilize this name for downstream tools
|
2017-07-23 17:31:04 +02:00
|
|
|
|
|
|
|
// Local Interrupts must be synchronized to the core clock
|
|
|
|
// before being passed into this module.
|
|
|
|
// This allows faster latency for interrupts which are already synchronized.
|
|
|
|
// The CLINT and PLIC outputs interrupts that are synchronous to the periphery clock,
|
|
|
|
// so may or may not need to be synchronized depending on the Tile's crossing type.
|
|
|
|
// Debug interrupt is definitely asynchronous in all cases.
|
|
|
|
val asyncIntXbar = LazyModule(new IntXbar)
|
|
|
|
asyncIntXbar.intnode := debug.intnode // debug
|
|
|
|
wrapper.asyncIntNode := asyncIntXbar.intnode
|
|
|
|
|
|
|
|
val periphIntXbar = LazyModule(new IntXbar)
|
|
|
|
periphIntXbar.intnode := clint.intnode // msip+mtip
|
|
|
|
periphIntXbar.intnode := plic.intnode // meip
|
2017-08-31 02:57:52 +02:00
|
|
|
if (tp.core.useVM) periphIntXbar.intnode := plic.intnode // seip
|
2017-07-23 17:31:04 +02:00
|
|
|
wrapper.periphIntNode := periphIntXbar.intnode
|
|
|
|
|
|
|
|
val coreIntXbar = LazyModule(new IntXbar)
|
|
|
|
lip.foreach { coreIntXbar.intnode := _ } // lip
|
|
|
|
wrapper.coreIntNode := coreIntXbar.intnode
|
|
|
|
|
2017-09-27 21:02:04 +02:00
|
|
|
wrapper.intOutputNode.foreach { case int =>
|
|
|
|
val rocketIntXing = LazyModule(new IntXing(wrapper.outputInterruptXingLatency))
|
2017-09-27 21:46:29 +02:00
|
|
|
FlipRendering { implicit p => rocketIntXing.intnode := int }
|
2017-09-27 21:02:04 +02:00
|
|
|
plic.intnode := rocketIntXing.intnode
|
|
|
|
}
|
2017-09-16 03:49:40 +02:00
|
|
|
|
2017-07-23 17:31:04 +02:00
|
|
|
wrapper
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
class ClockedRocketTileInputs(implicit val p: Parameters) extends ParameterizedBundle
|
|
|
|
with HasExternallyDrivenTileConstants
|
|
|
|
with Clocked
|
|
|
|
|
|
|
|
trait HasRocketTilesBundle {
|
|
|
|
val rocket_tile_inputs: Vec[ClockedRocketTileInputs]
|
|
|
|
}
|
|
|
|
|
2017-09-14 03:06:03 +02:00
|
|
|
trait HasRocketTilesModuleImp extends LazyModuleImp
|
2017-07-23 17:31:04 +02:00
|
|
|
with HasRocketTilesBundle
|
|
|
|
with HasResetVectorWire
|
|
|
|
with HasPeripheryDebugModuleImp {
|
|
|
|
val outer: HasRocketTiles
|
2017-09-02 02:50:54 +02:00
|
|
|
|
2017-10-04 21:11:37 +02:00
|
|
|
def resetVectorBits: Int = {
|
|
|
|
// Consider using the minimum over all widths, rather than enforcing homogeneity
|
|
|
|
val vectors = outer.rocket_tiles.map(_.module.io.reset_vector)
|
|
|
|
require(vectors.tail.forall(_.getWidth == vectors.head.getWidth))
|
|
|
|
vectors.head.getWidth
|
|
|
|
}
|
2017-10-05 09:26:44 +02:00
|
|
|
val rocket_tile_inputs = Wire(Vec(outer.nRocketTiles, new ClockedRocketTileInputs()(p.alterPartial {
|
2017-09-02 02:50:54 +02:00
|
|
|
case SharedMemoryTLEdge => outer.sharedMemoryTLEdge
|
2017-10-05 09:26:44 +02:00
|
|
|
})))
|
2017-07-23 17:31:04 +02:00
|
|
|
|
|
|
|
// Unconditionally wire up the non-diplomatic tile inputs
|
2017-07-26 01:35:31 +02:00
|
|
|
outer.rocket_tiles.map(_.module).zip(rocket_tile_inputs).foreach { case(tile, wire) =>
|
2017-07-23 17:31:04 +02:00
|
|
|
tile.clock := wire.clock
|
|
|
|
tile.reset := wire.reset
|
|
|
|
tile.io.hartid := wire.hartid
|
2017-09-02 02:50:54 +02:00
|
|
|
tile.io.reset_vector := wire.reset_vector
|
2017-07-23 17:31:04 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// Default values for tile inputs; may be overriden in other traits
|
2017-10-05 09:31:53 +02:00
|
|
|
rocket_tile_inputs.zip(outer.hartIdList).foreach { case(wire, i) =>
|
2017-07-23 17:31:04 +02:00
|
|
|
wire.clock := clock
|
|
|
|
wire.reset := reset
|
2017-10-05 09:26:44 +02:00
|
|
|
wire.hartid := UInt(i)
|
2017-09-02 02:50:54 +02:00
|
|
|
wire.reset_vector := global_reset_vector
|
2017-07-23 17:31:04 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
class RocketCoreplex(implicit p: Parameters) extends BaseCoreplex
|
|
|
|
with HasRocketTiles {
|
|
|
|
override lazy val module = new RocketCoreplexModule(this)
|
|
|
|
}
|
|
|
|
|
|
|
|
class RocketCoreplexModule[+L <: RocketCoreplex](_outer: L) extends BaseCoreplexModule(_outer)
|
|
|
|
with HasRocketTilesModuleImp
|