coreplex: RocketTileWrapper now HasCrossingHelper
This commit is contained in:
parent
9fe35382ea
commit
b48ab985d0
@ -12,12 +12,6 @@ import freechips.rocketchip.tile.{BaseTile, TileParams, SharedMemoryTLEdge, HasE
|
|||||||
import freechips.rocketchip.devices.debug.{HasPeripheryDebug, HasPeripheryDebugModuleImp}
|
import freechips.rocketchip.devices.debug.{HasPeripheryDebug, HasPeripheryDebugModuleImp}
|
||||||
import freechips.rocketchip.util._
|
import freechips.rocketchip.util._
|
||||||
|
|
||||||
/** Enumerates the three types of clock crossing between tiles and system bus */
|
|
||||||
sealed trait CoreplexClockCrossing
|
|
||||||
case class SynchronousCrossing(params: BufferParams = BufferParams.default) extends CoreplexClockCrossing
|
|
||||||
case class RationalCrossing(direction: RationalDirection = FastToSlow) extends CoreplexClockCrossing
|
|
||||||
case class AsynchronousCrossing(depth: Int, sync: Int = 3) extends CoreplexClockCrossing
|
|
||||||
|
|
||||||
/** BareCoreplex is the root class for creating a coreplex sub-system */
|
/** BareCoreplex is the root class for creating a coreplex sub-system */
|
||||||
abstract class BareCoreplex(implicit p: Parameters) extends LazyModule with BindingScope {
|
abstract class BareCoreplex(implicit p: Parameters) extends LazyModule with BindingScope {
|
||||||
lazy val dts = DTS(bindingTree)
|
lazy val dts = DTS(bindingTree)
|
||||||
|
@ -7,30 +7,34 @@ import freechips.rocketchip.config._
|
|||||||
import freechips.rocketchip.diplomacy._
|
import freechips.rocketchip.diplomacy._
|
||||||
import freechips.rocketchip.tilelink._
|
import freechips.rocketchip.tilelink._
|
||||||
import freechips.rocketchip.interrupts._
|
import freechips.rocketchip.interrupts._
|
||||||
|
import freechips.rocketchip.util._
|
||||||
|
|
||||||
|
/** Enumerates the three types of clock crossing between tiles and system bus */
|
||||||
|
sealed trait CoreplexClockCrossing
|
||||||
|
case class SynchronousCrossing(params: BufferParams = BufferParams.default) extends CoreplexClockCrossing
|
||||||
|
case class RationalCrossing(direction: RationalDirection = FastToSlow) extends CoreplexClockCrossing
|
||||||
|
case class AsynchronousCrossing(depth: Int, sync: Int = 3) extends CoreplexClockCrossing
|
||||||
|
|
||||||
trait HasCrossingHelper extends LazyScope
|
trait HasCrossingHelper extends LazyScope
|
||||||
{
|
{
|
||||||
this: LazyModule =>
|
this: LazyModule =>
|
||||||
val crossing: CoreplexClockCrossing
|
val crossing: CoreplexClockCrossing
|
||||||
|
|
||||||
def cross(x: TLCrossableNode, name: String): TLOutwardNode = {
|
def cross(x: TLCrossableNode): TLOutwardNode = {
|
||||||
val out = x.node.parentsOut.exists(_ eq this) // is the crossing exiting the wrapper?
|
val out = x.node.parentsOut.exists(_ eq this) // is the crossing exiting the wrapper?
|
||||||
crossing match {
|
crossing match {
|
||||||
case SynchronousCrossing(params) => {
|
case SynchronousCrossing(params) => {
|
||||||
val buffer = this { LazyModule(new TLBuffer(params)) }
|
// !!! Why does star resolution fail for tile with no slave devices?
|
||||||
buffer.suggestName(name + "SynchronousBuffer")
|
// this { TLBuffer(params)(x.node) }
|
||||||
buffer.node := x.node
|
x.node
|
||||||
buffer.node
|
|
||||||
}
|
}
|
||||||
case RationalCrossing(direction) => {
|
case RationalCrossing(direction) => {
|
||||||
def sourceGen = LazyModule(new TLRationalCrossingSource)
|
def sourceGen = LazyModule(new TLRationalCrossingSource)
|
||||||
def sinkGen = LazyModule(new TLRationalCrossingSink(direction))
|
def sinkGen = LazyModule(new TLRationalCrossingSink(direction))
|
||||||
val source = if (out) this { sourceGen } else sourceGen
|
val source = if (out) this { sourceGen } else sourceGen
|
||||||
val sink = if (out) sinkGen else this { sinkGen }
|
val sink = if (out) sinkGen else this { sinkGen }
|
||||||
source.suggestName(name + "RationalSource")
|
source.node :=? x.node
|
||||||
sink.suggestName(name + "RationalSink")
|
sink.node :=? source.node
|
||||||
source.node := x.node
|
|
||||||
sink.node := source.node
|
|
||||||
sink.node
|
sink.node
|
||||||
}
|
}
|
||||||
case AsynchronousCrossing(depth, sync) => {
|
case AsynchronousCrossing(depth, sync) => {
|
||||||
@ -38,27 +42,29 @@ trait HasCrossingHelper extends LazyScope
|
|||||||
def sinkGen = LazyModule(new TLAsyncCrossingSink(depth, sync))
|
def sinkGen = LazyModule(new TLAsyncCrossingSink(depth, sync))
|
||||||
val source = if (out) this { sourceGen } else sourceGen
|
val source = if (out) this { sourceGen } else sourceGen
|
||||||
val sink = if (out) sinkGen else this { sinkGen }
|
val sink = if (out) sinkGen else this { sinkGen }
|
||||||
source.suggestName(name + "AsynchronousSource")
|
source.node :=? x.node
|
||||||
sink.suggestName(name + "AsynchronousSink")
|
sink.node :=? source.node
|
||||||
source.node := x.node
|
|
||||||
sink.node := source.node
|
|
||||||
sink.node
|
sink.node
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
def cross(x: IntCrossableNode, name: String, alreadyRegistered: Boolean = false): IntOutwardNode = {
|
def cross(
|
||||||
|
name: Option[String] = None,
|
||||||
|
alreadyRegistered: Boolean = false,
|
||||||
|
overrideCrossing: Option[CoreplexClockCrossing] = None)
|
||||||
|
(x: IntCrossableNode): IntOutwardNode = {
|
||||||
val out = x.node.parentsOut.exists(_ eq this) // is the crossing exiting the wrapper?
|
val out = x.node.parentsOut.exists(_ eq this) // is the crossing exiting the wrapper?
|
||||||
crossing match {
|
overrideCrossing.getOrElse(crossing) match {
|
||||||
case SynchronousCrossing(_) => {
|
case SynchronousCrossing(_) => {
|
||||||
def sourceGen = LazyModule(new IntSyncCrossingSource(alreadyRegistered))
|
def sourceGen = LazyModule(new IntSyncCrossingSource(alreadyRegistered))
|
||||||
def sinkGen = LazyModule(new IntSyncCrossingSink(0))
|
def sinkGen = LazyModule(new IntSyncCrossingSink(0))
|
||||||
val source = if (out) this { sourceGen } else sourceGen
|
val source = if (out) this { sourceGen } else sourceGen
|
||||||
val sink = if (out) sinkGen else this { sinkGen }
|
val sink = if (out) sinkGen else this { sinkGen }
|
||||||
source.suggestName(name + "SyncSource")
|
name.map(_ + "SyncSource").foreach(source.suggestName)
|
||||||
sink.suggestName(name + "SyncSink")
|
name.map(_ + "SyncSink").foreach(sink.suggestName)
|
||||||
source.node := x.node
|
source.node :=? x.node
|
||||||
sink.node := source.node
|
sink.node :=? source.node
|
||||||
sink.node
|
sink.node
|
||||||
}
|
}
|
||||||
case RationalCrossing(_) => {
|
case RationalCrossing(_) => {
|
||||||
@ -66,10 +72,10 @@ trait HasCrossingHelper extends LazyScope
|
|||||||
def sinkGen = LazyModule(new IntSyncCrossingSink(1))
|
def sinkGen = LazyModule(new IntSyncCrossingSink(1))
|
||||||
val source = if (out) this { sourceGen } else sourceGen
|
val source = if (out) this { sourceGen } else sourceGen
|
||||||
val sink = if (out) sinkGen else this { sinkGen }
|
val sink = if (out) sinkGen else this { sinkGen }
|
||||||
source.suggestName(name + "SyncSource")
|
name.map(_ + "SyncSource").foreach(source.suggestName)
|
||||||
sink.suggestName(name + "SyncSink")
|
name.map(_ + "SyncSink").foreach(sink.suggestName)
|
||||||
source.node := x.node
|
source.node :=? x.node
|
||||||
sink.node := source.node
|
sink.node :=? source.node
|
||||||
sink.node
|
sink.node
|
||||||
}
|
}
|
||||||
case AsynchronousCrossing(_, sync) => {
|
case AsynchronousCrossing(_, sync) => {
|
||||||
@ -77,10 +83,10 @@ trait HasCrossingHelper extends LazyScope
|
|||||||
def sinkGen = LazyModule(new IntSyncCrossingSink(sync))
|
def sinkGen = LazyModule(new IntSyncCrossingSink(sync))
|
||||||
val source = if (out) this { sourceGen } else sourceGen
|
val source = if (out) this { sourceGen } else sourceGen
|
||||||
val sink = if (out) sinkGen else this { sinkGen }
|
val sink = if (out) sinkGen else this { sinkGen }
|
||||||
source.suggestName(name + "SyncSource")
|
name.map(_ + "SyncSource").foreach(source.suggestName)
|
||||||
sink.suggestName(name + "SyncSink")
|
name.map(_ + "SyncSink").foreach(sink.suggestName)
|
||||||
source.node := x.node
|
source.node :=? x.node
|
||||||
sink.node := source.node
|
sink.node :=? source.node
|
||||||
sink.node
|
sink.node
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -31,27 +31,26 @@ class PeripheryBus(params: PeripheryBusParams)(implicit p: Parameters) extends T
|
|||||||
TLFragmenter(params.beatBytes, maxXferBytes)(outwardBufNode)
|
TLFragmenter(params.beatBytes, maxXferBytes)(outwardBufNode)
|
||||||
}
|
}
|
||||||
|
|
||||||
def toSyncSlaves(adapt: TLOutwardNode => TLOutwardNode, name: Option[String]): TLOutwardNode = adapt(outwardBufNode)
|
|
||||||
|
|
||||||
def toAsyncSlaves(sync: Int, adapt: TLOutwardNode => TLOutwardNode, name: Option[String]): TLAsyncOutwardNode = SinkCardinality { implicit p =>
|
|
||||||
val source = LazyModule(new TLAsyncCrossingSource(sync))
|
|
||||||
name.foreach{ n => source.suggestName(s"${busName}_${n}_TLAsyncCrossingSource")}
|
|
||||||
source.node :*= adapt(outwardNode)
|
|
||||||
source.node
|
|
||||||
}
|
|
||||||
|
|
||||||
def toRationalSlaves(adapt: TLOutwardNode => TLOutwardNode, name: Option[String]): TLRationalOutwardNode = SinkCardinality { implicit p =>
|
|
||||||
val source = LazyModule(new TLRationalCrossingSource())
|
|
||||||
name.foreach{ n => source.suggestName(s"${busName}_${n}_TLRationalCrossingSource")}
|
|
||||||
source.node :*= adapt(outwardNode)
|
|
||||||
source.node
|
|
||||||
}
|
|
||||||
|
|
||||||
val fromSystemBus: TLInwardNode = {
|
val fromSystemBus: TLInwardNode = {
|
||||||
val atomics = LazyModule(new TLAtomicAutomata(arithmetic = params.arithmetic))
|
val atomics = LazyModule(new TLAtomicAutomata(arithmetic = params.arithmetic))
|
||||||
inwardBufNode := atomics.node
|
inwardBufNode := atomics.node
|
||||||
atomics.node
|
atomics.node
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def toTile(
|
||||||
|
adapt: TLOutwardNode => TLOutwardNode,
|
||||||
|
to: TLInwardNode,
|
||||||
|
name: Option[String] = None) {
|
||||||
|
this {
|
||||||
|
LazyScope(s"${busName}ToTile${name.getOrElse("")}") {
|
||||||
|
SinkCardinality { implicit p =>
|
||||||
|
FlipRendering { implicit p =>
|
||||||
|
to :*= adapt(outwardNode)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Provides buses that serve as attachment points,
|
/** Provides buses that serve as attachment points,
|
||||||
|
@ -18,6 +18,7 @@ case class TileMasterPortParams(
|
|||||||
addBuffers: Int = 0,
|
addBuffers: Int = 0,
|
||||||
blockerCtrlAddr: Option[BigInt] = None,
|
blockerCtrlAddr: Option[BigInt] = None,
|
||||||
cork: Option[Boolean] = None) {
|
cork: Option[Boolean] = None) {
|
||||||
|
|
||||||
def adapt(coreplex: HasPeripheryBus)
|
def adapt(coreplex: HasPeripheryBus)
|
||||||
(masterNode: TLOutwardNode)
|
(masterNode: TLOutwardNode)
|
||||||
(implicit p: Parameters, sourceInfo: SourceInfo): TLOutwardNode = {
|
(implicit p: Parameters, sourceInfo: SourceInfo): TLOutwardNode = {
|
||||||
@ -29,16 +30,15 @@ case class TileMasterPortParams(
|
|||||||
val tile_master_fixer = LazyModule(new TLFIFOFixer(TLFIFOFixer.allUncacheable))
|
val tile_master_fixer = LazyModule(new TLFIFOFixer(TLFIFOFixer.allUncacheable))
|
||||||
val tile_master_buffer = LazyModule(new TLBufferChain(addBuffers))
|
val tile_master_buffer = LazyModule(new TLBufferChain(addBuffers))
|
||||||
|
|
||||||
tile_master_blocker.foreach { _.controlNode := coreplex.pbus.toVariableWidthSlaves }
|
val node: Option[TLNode] = TLNodeChain(List(
|
||||||
|
Some(tile_master_buffer.node),
|
||||||
|
Some(tile_master_fixer.node),
|
||||||
|
tile_master_blocker.map(_.node),
|
||||||
|
tile_master_cork.map(_.node)).flatten)
|
||||||
|
|
||||||
val node: Option[TLNode] = SourceCardinality { implicit p =>
|
tile_master_blocker.foreach { _.controlNode := coreplex.pbus.toVariableWidthSlaves }
|
||||||
TLNodeChain(List(
|
|
||||||
Some(tile_master_buffer.node),
|
|
||||||
Some(tile_master_fixer.node),
|
|
||||||
tile_master_blocker.map(_.node),
|
|
||||||
tile_master_cork.map(_.node)).flatten)
|
|
||||||
}
|
|
||||||
node.foreach { _ :=* masterNode }
|
node.foreach { _ :=* masterNode }
|
||||||
|
|
||||||
node.getOrElse(masterNode)
|
node.getOrElse(masterNode)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -46,6 +46,7 @@ case class TileMasterPortParams(
|
|||||||
case class TileSlavePortParams(
|
case class TileSlavePortParams(
|
||||||
addBuffers: Int = 0,
|
addBuffers: Int = 0,
|
||||||
blockerCtrlAddr: Option[BigInt] = None) {
|
blockerCtrlAddr: Option[BigInt] = None) {
|
||||||
|
|
||||||
def adapt(coreplex: HasPeripheryBus)
|
def adapt(coreplex: HasPeripheryBus)
|
||||||
(masterNode: TLOutwardNode)
|
(masterNode: TLOutwardNode)
|
||||||
(implicit p: Parameters, sourceInfo: SourceInfo): TLOutwardNode = {
|
(implicit p: Parameters, sourceInfo: SourceInfo): TLOutwardNode = {
|
||||||
@ -55,14 +56,13 @@ case class TileSlavePortParams(
|
|||||||
.map(bp => LazyModule(new BasicBusBlocker(bp)))
|
.map(bp => LazyModule(new BasicBusBlocker(bp)))
|
||||||
val tile_slave_buffer = LazyModule(new TLBufferChain(addBuffers))
|
val tile_slave_buffer = LazyModule(new TLBufferChain(addBuffers))
|
||||||
|
|
||||||
tile_slave_blocker.foreach { _.controlNode := coreplex.pbus.toVariableWidthSlaves }
|
val node: Option[TLNode] = TLNodeChain(List(
|
||||||
|
Some(tile_slave_buffer.node),
|
||||||
|
tile_slave_blocker.map(_.node)).flatten)
|
||||||
|
|
||||||
val node: Option[TLNode] = SinkCardinality { implicit p =>
|
tile_slave_blocker.foreach { _.controlNode := coreplex.pbus.toVariableWidthSlaves }
|
||||||
TLNodeChain(List(
|
|
||||||
Some(tile_slave_buffer.node),
|
|
||||||
tile_slave_blocker.map(_.node)).flatten)
|
|
||||||
}
|
|
||||||
node.foreach { _ :*= masterNode }
|
node.foreach { _ :*= masterNode }
|
||||||
|
|
||||||
node.getOrElse(masterNode)
|
node.getOrElse(masterNode)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -70,7 +70,8 @@ case class TileSlavePortParams(
|
|||||||
case class RocketCrossingParams(
|
case class RocketCrossingParams(
|
||||||
crossingType: CoreplexClockCrossing = SynchronousCrossing(),
|
crossingType: CoreplexClockCrossing = SynchronousCrossing(),
|
||||||
master: TileMasterPortParams = TileMasterPortParams(),
|
master: TileMasterPortParams = TileMasterPortParams(),
|
||||||
slave: TileSlavePortParams = TileSlavePortParams()) {
|
slave: TileSlavePortParams = TileSlavePortParams(),
|
||||||
|
boundaryBuffers: Boolean = false) {
|
||||||
def knownRatio: Option[Int] = crossingType match {
|
def knownRatio: Option[Int] = crossingType match {
|
||||||
case RationalCrossing(_) => Some(2)
|
case RationalCrossing(_) => Some(2)
|
||||||
case _ => None
|
case _ => None
|
||||||
@ -95,67 +96,72 @@ trait HasRocketTiles extends HasTiles
|
|||||||
case NumRocketTiles => crossingParams
|
case NumRocketTiles => crossingParams
|
||||||
case _ => throw new Exception("RocketCrossingKey.size must == 1 or == RocketTilesKey.size")
|
case _ => throw new Exception("RocketCrossingKey.size must == 1 or == RocketTilesKey.size")
|
||||||
}
|
}
|
||||||
|
private val crossingTuples = localIntNodes.zip(tileParams).zip(crossings)
|
||||||
|
|
||||||
// Make a wrapper for each tile that will wire it to coreplex devices and crossbars,
|
// Make a wrapper for each tile that will wire it to coreplex devices and crossbars,
|
||||||
// according to the specified type of clock crossing.
|
// according to the specified type of clock crossing.
|
||||||
private val crossingTuples = localIntNodes.zip(tileParams).zip(crossings)
|
|
||||||
val tiles: Seq[BaseTile] = crossingTuples.map { case ((lip, tp), crossing) =>
|
val tiles: Seq[BaseTile] = crossingTuples.map { case ((lip, tp), crossing) =>
|
||||||
val pWithExtra = p.alterPartial {
|
// For legacy reasons, it is convenient to store some state
|
||||||
case TileKey => tp
|
// in the global Parameters about the specific tile being built now
|
||||||
case BuildRoCC => tp.rocc
|
val wrapper = LazyModule(new RocketTileWrapper(
|
||||||
case SharedMemoryTLEdge => sharedMemoryTLEdge
|
params = tp,
|
||||||
case RocketCrossingKey => List(crossing)
|
crossing = crossing.crossingType,
|
||||||
}
|
boundaryBuffers = crossing.boundaryBuffers
|
||||||
|
)(p.alterPartial {
|
||||||
|
case TileKey => tp
|
||||||
|
case BuildRoCC => tp.rocc
|
||||||
|
case SharedMemoryTLEdge => sharedMemoryTLEdge
|
||||||
|
case RocketCrossingKey => List(crossing)
|
||||||
|
})
|
||||||
|
).suggestName(tp.name)
|
||||||
|
|
||||||
val wrapper = crossing.crossingType match {
|
// Connect the master ports of the tile to the system bus
|
||||||
case SynchronousCrossing(params) => {
|
sbus.fromTile(
|
||||||
val wrapper = LazyModule(new SyncRocketTile(tp)(pWithExtra))
|
adapt = {x: TLOutwardNode => wrapper.cross(x) } andThen
|
||||||
sbus.fromSyncTiles(params, crossing.master.adapt(this) _, tp.name) :=* wrapper.masterNode
|
crossing.master.adapt(this) _,
|
||||||
FlipRendering { implicit p => wrapper.slaveNode:*= pbus.toSyncSlaves(crossing.slave.adapt(this) _, tp.name) }
|
from = wrapper.masterNode,
|
||||||
wrapper
|
name = tp.name)
|
||||||
}
|
|
||||||
case AsynchronousCrossing(depth, sync) => {
|
|
||||||
val wrapper = LazyModule(new AsyncRocketTile(tp)(pWithExtra))
|
|
||||||
sbus.fromAsyncTiles(depth, sync, crossing.master.adapt(this) _, tp.name) :=* wrapper.masterNode
|
|
||||||
FlipRendering { implicit p => wrapper.slaveNode :*= pbus.toAsyncSlaves(sync, crossing.slave.adapt(this) _, tp.name) }
|
|
||||||
wrapper
|
|
||||||
}
|
|
||||||
case RationalCrossing(direction) => {
|
|
||||||
val wrapper = LazyModule(new RationalRocketTile(tp)(pWithExtra))
|
|
||||||
sbus.fromRationalTiles(direction, crossing.master.adapt(this) _, tp.name) :=* wrapper.masterNode
|
|
||||||
FlipRendering { implicit p => wrapper.slaveNode :*= pbus.toRationalSlaves(crossing.slave.adapt(this) _, tp.name) }
|
|
||||||
wrapper
|
|
||||||
}
|
|
||||||
}
|
|
||||||
tp.name.foreach(wrapper.suggestName) // Try to stabilize this name for downstream tools
|
|
||||||
|
|
||||||
// Local Interrupts must be synchronized to the core clock
|
// Connect the slave ports of the tile to the periphery bus
|
||||||
// before being passed into this module.
|
pbus.toTile(
|
||||||
// This allows faster latency for interrupts which are already synchronized.
|
adapt = {x: TLOutwardNode => wrapper.cross(x) } compose
|
||||||
// The CLINT and PLIC outputs interrupts that are synchronous to the periphery clock,
|
crossing.slave.adapt(this) _,
|
||||||
// so may or may not need to be synchronized depending on the Tile's crossing type.
|
to = wrapper.slaveNode,
|
||||||
// Debug interrupt is definitely asynchronous in all cases.
|
name = tp.name)
|
||||||
val asyncIntXbar = LazyModule(new IntXbar)
|
|
||||||
asyncIntXbar.suggestName("asyncIntXbar")
|
|
||||||
asyncIntXbar.intnode := debug.intnode // debug
|
|
||||||
wrapper.asyncIntNode := asyncIntXbar.intnode
|
|
||||||
|
|
||||||
val periphIntXbar = LazyModule(new IntXbar)
|
// Handle all the different types of interrupts crossing to or from the tile:
|
||||||
periphIntXbar.suggestName("periphIntXbar")
|
// 1. Debug interrupt is definitely asynchronous in all cases.
|
||||||
periphIntXbar.intnode := clint.intnode // msip+mtip
|
// 2. The CLINT and PLIC output interrupts are synchronous to the periphery clock,
|
||||||
periphIntXbar.intnode := plic.intnode // meip
|
// 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.
|
||||||
|
|
||||||
|
val asyncIntXbar = LazyModule(new IntXbar).suggestName(tp.name.map(_ + "AsyncIntXbar"))
|
||||||
|
asyncIntXbar.intnode := debug.intnode // debug
|
||||||
|
wrapper.intXbar.intnode := wrapper.cross( // 1. always crosses
|
||||||
|
name = tp.name.map(_ + "AsyncIntXbar"),
|
||||||
|
overrideCrossing = Some(AsynchronousCrossing(8,3))
|
||||||
|
)(x = asyncIntXbar.intnode)
|
||||||
|
|
||||||
|
val periphIntXbar = LazyModule(new IntXbar).suggestName(tp.name.map(_ + "PeriphIntXbar"))
|
||||||
|
periphIntXbar.intnode := clint.intnode // msip+mtip
|
||||||
|
periphIntXbar.intnode := plic.intnode // meip
|
||||||
if (tp.core.useVM) periphIntXbar.intnode := plic.intnode // seip
|
if (tp.core.useVM) periphIntXbar.intnode := plic.intnode // seip
|
||||||
wrapper.periphIntNode := periphIntXbar.intnode
|
wrapper.intXbar.intnode := wrapper.cross( // 2. conditionally crosses
|
||||||
|
name = tp.name.map(_ + "PeriphIntXbar")
|
||||||
|
)(x = periphIntXbar.intnode)
|
||||||
|
|
||||||
val coreIntXbar = LazyModule(new IntXbar)
|
val coreIntXbar = LazyModule(new IntXbar).suggestName(tp.name.map(_ + "CoreIntXbar"))
|
||||||
coreIntXbar.suggestName("coreIntXbar")
|
lip.foreach { coreIntXbar.intnode := _ } // lip
|
||||||
lip.foreach { coreIntXbar.intnode := _ } // lip
|
wrapper.intXbar.intnode := coreIntXbar.intnode // 3. never crosses
|
||||||
wrapper.coreIntNode := coreIntXbar.intnode
|
|
||||||
|
|
||||||
wrapper.intOutputNode.foreach { case int =>
|
wrapper.rocket.intOutputNode.foreach { i => // 4. conditionally crosses
|
||||||
val rocketIntXing = LazyModule(new IntXing(wrapper.outputInterruptXingLatency))
|
plic.intnode := FlipRendering { implicit p =>
|
||||||
FlipRendering { implicit p => rocketIntXing.intnode := int }
|
wrapper.cross(name = tp.name.map(_ + "PeriphIntOutput"))(x = i)
|
||||||
plic.intnode := rocketIntXing.intnode
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
wrapper
|
wrapper
|
||||||
|
@ -52,28 +52,17 @@ class SystemBus(params: SystemBusParams)(implicit p: Parameters) extends TLBusWr
|
|||||||
|
|
||||||
def fromFrontBus: TLInwardNode = master_splitter.node
|
def fromFrontBus: TLInwardNode = master_splitter.node
|
||||||
|
|
||||||
def fromSyncTiles(params: BufferParams, adapt: TLOutwardNode => TLOutwardNode, name: Option[String] = None): TLInwardNode = this {
|
def fromTile(
|
||||||
val tile_sink = LazyModule(new TLBuffer(params))
|
adapt: TLOutwardNode => TLOutwardNode,
|
||||||
name.foreach { n => tile_sink.suggestName(s"${busName}_${n}_TLBuffer") }
|
from: TLOutwardNode,
|
||||||
|
name: Option[String] = None) {
|
||||||
master_splitter.node :=* adapt(tile_sink.node)
|
this {
|
||||||
tile_sink.node
|
LazyScope(s"${busName}FromTile${name.getOrElse("")}") {
|
||||||
}
|
SourceCardinality { implicit p =>
|
||||||
|
master_splitter.node :=* adapt(from)
|
||||||
def fromRationalTiles(dir: RationalDirection, adapt: TLOutwardNode => TLOutwardNode, name: Option[String] = None): TLRationalInwardNode = this {
|
}
|
||||||
val tile_sink = LazyModule(new TLRationalCrossingSink(direction = dir))
|
}
|
||||||
name.foreach { n => tile_sink.suggestName(s"${busName}_${n}_TLRationalCrossingSink") }
|
}
|
||||||
|
|
||||||
master_splitter.node :=* adapt(tile_sink.node)
|
|
||||||
tile_sink.node
|
|
||||||
}
|
|
||||||
|
|
||||||
def fromAsyncTiles(depth: Int, sync: Int, adapt: TLOutwardNode => TLOutwardNode, name: Option[String] = None): TLAsyncInwardNode = this {
|
|
||||||
val tile_sink = LazyModule(new TLAsyncCrossingSink(depth, sync))
|
|
||||||
name.foreach { n => tile_sink.suggestName(s"${busName}_${n}_TLAsyncCrossingSink") }
|
|
||||||
|
|
||||||
master_splitter.node :=* adapt(tile_sink.node)
|
|
||||||
tile_sink.node
|
|
||||||
}
|
}
|
||||||
|
|
||||||
def fromSyncPorts(params: BufferParams = BufferParams.default, name: Option[String] = None): TLInwardNode = {
|
def fromSyncPorts(params: BufferParams = BufferParams.default, name: Option[String] = None): TLInwardNode = {
|
||||||
|
@ -25,8 +25,13 @@ abstract class LazyModule()(implicit val p: Parameters)
|
|||||||
LazyModule.scope = Some(this)
|
LazyModule.scope = Some(this)
|
||||||
parent.foreach(p => p.children = this :: p.children)
|
parent.foreach(p => p.children = this :: p.children)
|
||||||
|
|
||||||
|
// suggestedName accumulates Some(names), taking the final one. Nones are ignored.
|
||||||
private var suggestedName: Option[String] = None
|
private var suggestedName: Option[String] = None
|
||||||
def suggestName(x: String) = suggestedName = Some(x)
|
def suggestName(x: String): this.type = suggestName(Some(x))
|
||||||
|
def suggestName(x: Option[String]): this.type = {
|
||||||
|
x.foreach { n => suggestedName = Some(n) }
|
||||||
|
this
|
||||||
|
}
|
||||||
|
|
||||||
private lazy val childNames =
|
private lazy val childNames =
|
||||||
getClass.getMethods.filter { m =>
|
getClass.getMethods.filter { m =>
|
||||||
|
@ -25,8 +25,10 @@ class GroundTestCoreplex(implicit p: Parameters) extends BaseCoreplex
|
|||||||
})
|
})
|
||||||
)}
|
)}
|
||||||
|
|
||||||
tiles.flatMap(_.dcacheOpt).foreach {
|
tiles.flatMap(_.dcacheOpt).foreach { dc =>
|
||||||
sbus.fromSyncTiles(BufferParams.default, TileMasterPortParams().adapt(this) _) :=* _.node
|
sbus.fromTile(
|
||||||
|
adapt = TileMasterPortParams(addBuffers = 1).adapt(this) _,
|
||||||
|
from = dc.node)
|
||||||
}
|
}
|
||||||
|
|
||||||
val pbusRAM = LazyModule(new TLRAM(AddressSet(testRamAddr, 0xffff), true, false, pbus.beatBytes))
|
val pbusRAM = LazyModule(new TLRAM(AddressSet(testRamAddr, 0xffff), true, false, pbus.beatBytes))
|
||||||
|
@ -19,7 +19,6 @@ case class RocketTileParams(
|
|||||||
rocc: Seq[RoCCParams] = Nil,
|
rocc: Seq[RoCCParams] = Nil,
|
||||||
btb: Option[BTBParams] = Some(BTBParams()),
|
btb: Option[BTBParams] = Some(BTBParams()),
|
||||||
dataScratchpadBytes: Int = 0,
|
dataScratchpadBytes: Int = 0,
|
||||||
boundaryBuffers: Boolean = false,
|
|
||||||
trace: Boolean = false,
|
trace: Boolean = false,
|
||||||
hcfOnUncorrectable: Boolean = false,
|
hcfOnUncorrectable: Boolean = false,
|
||||||
name: Option[String] = Some("tile"),
|
name: Option[String] = Some("tile"),
|
||||||
@ -188,38 +187,29 @@ class RocketTileWrapperBundle[+L <: RocketTileWrapper](_outer: L) extends BaseTi
|
|||||||
val halt_and_catch_fire = _outer.rocket.module.io.halt_and_catch_fire.map(_.cloneType)
|
val halt_and_catch_fire = _outer.rocket.module.io.halt_and_catch_fire.map(_.cloneType)
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract class RocketTileWrapper(rtp: RocketTileParams)(implicit p: Parameters) extends BaseTile(rtp) {
|
class RocketTileWrapper(
|
||||||
val rocket = LazyModule(new RocketTile(rtp))
|
params: RocketTileParams,
|
||||||
val asyncIntNode : IntInwardNode
|
val crossing: CoreplexClockCrossing,
|
||||||
val periphIntNode : IntInwardNode
|
val boundaryBuffers: Boolean = false)
|
||||||
val coreIntNode : IntInwardNode
|
(implicit p: Parameters) extends BaseTile(params) with HasCrossingHelper {
|
||||||
val intOutputNode = rocket.intOutputNode
|
|
||||||
|
val rocket = LazyModule(new RocketTile(params))
|
||||||
|
|
||||||
|
val masterBuffer = LazyModule(new TLBuffer(BufferParams.none, BufferParams.flow, BufferParams.none, BufferParams.flow, BufferParams(1)))
|
||||||
|
val masterNode: TLOutwardNode = if (boundaryBuffers) {
|
||||||
|
masterBuffer.node :=* rocket.masterNode
|
||||||
|
masterBuffer.node
|
||||||
|
} else { rocket.masterNode }
|
||||||
|
|
||||||
|
val slaveBuffer = LazyModule(new TLBuffer(BufferParams.flow, BufferParams.none, BufferParams.none, BufferParams.none, BufferParams.none))
|
||||||
|
val slaveNode: TLInwardNode = DisableMonitors { implicit p => if (boundaryBuffers) {
|
||||||
|
rocket.slaveNode :*= slaveBuffer.node
|
||||||
|
slaveBuffer.node
|
||||||
|
} else { rocket.slaveNode } }
|
||||||
|
|
||||||
val intXbar = LazyModule(new IntXbar)
|
val intXbar = LazyModule(new IntXbar)
|
||||||
|
|
||||||
rocket.intNode := intXbar.intnode
|
rocket.intNode := intXbar.intnode
|
||||||
|
|
||||||
def optionalMasterBuffer(in: TLOutwardNode): TLOutwardNode = {
|
|
||||||
if (rtp.boundaryBuffers) {
|
|
||||||
val mbuf = LazyModule(new TLBuffer(BufferParams.none, BufferParams.flow, BufferParams.none, BufferParams.flow, BufferParams(1)))
|
|
||||||
mbuf.node :=* in
|
|
||||||
mbuf.node
|
|
||||||
} else {
|
|
||||||
in
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
def optionalSlaveBuffer(out: TLInwardNode): TLInwardNode = {
|
|
||||||
if (rtp.boundaryBuffers) {
|
|
||||||
val sbuf = LazyModule(new TLBuffer(BufferParams.flow, BufferParams.none, BufferParams.none, BufferParams.none, BufferParams.none))
|
|
||||||
DisableMonitors { implicit p => out :*= sbuf.node }
|
|
||||||
sbuf.node
|
|
||||||
} else {
|
|
||||||
out
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
def outputInterruptXingLatency: Int
|
|
||||||
|
|
||||||
override lazy val module = new BaseTileModule(this, () => new RocketTileWrapperBundle(this)) {
|
override lazy val module = new BaseTileModule(this, () => new RocketTileWrapperBundle(this)) {
|
||||||
// signals that do not change based on crossing type:
|
// signals that do not change based on crossing type:
|
||||||
rocket.module.io.hartid := io.hartid
|
rocket.module.io.hartid := io.hartid
|
||||||
@ -228,76 +218,3 @@ abstract class RocketTileWrapper(rtp: RocketTileParams)(implicit p: Parameters)
|
|||||||
io.halt_and_catch_fire.foreach { _ := rocket.module.io.halt_and_catch_fire.get }
|
io.halt_and_catch_fire.foreach { _ := rocket.module.io.halt_and_catch_fire.get }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class SyncRocketTile(rtp: RocketTileParams)(implicit p: Parameters) extends RocketTileWrapper(rtp) {
|
|
||||||
val masterNode = optionalMasterBuffer(rocket.masterNode)
|
|
||||||
val slaveNode = optionalSlaveBuffer(rocket.slaveNode)
|
|
||||||
|
|
||||||
// Fully async interrupts need synchronizers.
|
|
||||||
// Others need no synchronization.
|
|
||||||
val xing = LazyModule(new IntXing(3))
|
|
||||||
val asyncIntNode = xing.intnode
|
|
||||||
|
|
||||||
val periphIntNode = IntIdentityNode()
|
|
||||||
val coreIntNode = IntIdentityNode()
|
|
||||||
|
|
||||||
// order here matters
|
|
||||||
intXbar.intnode := xing.intnode
|
|
||||||
intXbar.intnode := periphIntNode
|
|
||||||
intXbar.intnode := coreIntNode
|
|
||||||
|
|
||||||
def outputInterruptXingLatency = 0
|
|
||||||
}
|
|
||||||
|
|
||||||
class AsyncRocketTile(rtp: RocketTileParams)(implicit p: Parameters) extends RocketTileWrapper(rtp) {
|
|
||||||
val source = LazyModule(new TLAsyncCrossingSource)
|
|
||||||
source.node :=* rocket.masterNode
|
|
||||||
val masterNode = source.node
|
|
||||||
|
|
||||||
val sink = LazyModule(new TLAsyncCrossingSink)
|
|
||||||
DisableMonitors { implicit p => rocket.slaveNode :*= sink.node }
|
|
||||||
val slaveNode = sink.node
|
|
||||||
|
|
||||||
// Fully async interrupts need synchronizers,
|
|
||||||
// as do those coming from the periphery clock.
|
|
||||||
// Others need no synchronization.
|
|
||||||
val asyncXing = LazyModule(new IntXing(3))
|
|
||||||
val periphXing = LazyModule(new IntXing(3))
|
|
||||||
val asyncIntNode = asyncXing.intnode
|
|
||||||
val periphIntNode = periphXing.intnode
|
|
||||||
val coreIntNode = IntIdentityNode()
|
|
||||||
|
|
||||||
// order here matters
|
|
||||||
intXbar.intnode := asyncXing.intnode
|
|
||||||
intXbar.intnode := periphXing.intnode
|
|
||||||
intXbar.intnode := coreIntNode
|
|
||||||
|
|
||||||
def outputInterruptXingLatency = 3
|
|
||||||
}
|
|
||||||
|
|
||||||
class RationalRocketTile(rtp: RocketTileParams)(implicit p: Parameters) extends RocketTileWrapper(rtp) {
|
|
||||||
val source = LazyModule(new TLRationalCrossingSource)
|
|
||||||
source.node :=* optionalMasterBuffer(rocket.masterNode)
|
|
||||||
val masterNode = source.node
|
|
||||||
|
|
||||||
val sink = LazyModule(new TLRationalCrossingSink(SlowToFast))
|
|
||||||
DisableMonitors { implicit p => optionalSlaveBuffer(rocket.slaveNode) :*= sink.node }
|
|
||||||
val slaveNode = sink.node
|
|
||||||
|
|
||||||
// Fully async interrupts need synchronizers.
|
|
||||||
// Those coming from periphery clock need a
|
|
||||||
// rational synchronizer.
|
|
||||||
// Others need no synchronization.
|
|
||||||
val asyncXing = LazyModule(new IntXing(3))
|
|
||||||
val periphXing = LazyModule(new IntXing(1))
|
|
||||||
val asyncIntNode = asyncXing.intnode
|
|
||||||
val periphIntNode = periphXing.intnode
|
|
||||||
val coreIntNode = IntIdentityNode()
|
|
||||||
|
|
||||||
// order here matters
|
|
||||||
intXbar.intnode := asyncXing.intnode
|
|
||||||
intXbar.intnode := periphXing.intnode
|
|
||||||
intXbar.intnode := coreIntNode
|
|
||||||
|
|
||||||
def outputInterruptXingLatency = 1
|
|
||||||
}
|
|
||||||
|
Loading…
Reference in New Issue
Block a user