1
0

Merge pull request #1065 from freechipsproject/better-bus-wrappers

Better crossings deployed to bus and tile wrappers
This commit is contained in:
Wesley W. Terpstra 2017-10-26 16:48:38 -07:00 committed by GitHub
commit 91d8a97f1a
38 changed files with 686 additions and 614 deletions

View File

@ -6,7 +6,7 @@ import Chisel._
import freechips.rocketchip.config.Parameters
import freechips.rocketchip.diplomacy._
import freechips.rocketchip.regmapper._
import freechips.rocketchip.tilelink.{IntSourceNode, IntSourcePortSimple}
import freechips.rocketchip.interrupts.{IntSourceNode, IntSourcePortSimple}
import freechips.rocketchip.util.{HeterogeneousBag, MaskGen}
import scala.math.{min,max}

View File

@ -6,7 +6,7 @@ import Chisel._
import freechips.rocketchip.config.Parameters
import freechips.rocketchip.diplomacy._
import freechips.rocketchip.regmapper._
import freechips.rocketchip.tilelink.{IntSourceNode, IntSourcePortSimple}
import freechips.rocketchip.interrupts.{IntSourceNode, IntSourcePortSimple}
import freechips.rocketchip.util.HeterogeneousBag
import scala.math.{min,max}

View File

@ -8,6 +8,7 @@ import freechips.rocketchip.config.Parameters
import freechips.rocketchip.diplomacy._
import freechips.rocketchip.tilelink._
import freechips.rocketchip.util._
import freechips.rocketchip.coreplex.{CrossingWrapper, AsynchronousCrossing}
class AXI4AsyncCrossingSource(sync: Int = 3)(implicit p: Parameters) extends LazyModule
{
@ -61,6 +62,7 @@ object AXI4AsyncCrossingSink
}
}
@deprecated("AXI4AsyncCrossing is fragile. Use AXI4AsyncCrossingSource and AXI4AsyncCrossingSink", "rocket-chip 1.2")
class AXI4AsyncCrossing(depth: Int = 8, sync: Int = 3)(implicit p: Parameters) extends LazyModule
{
val source = LazyModule(new AXI4AsyncCrossingSource(sync))
@ -89,28 +91,21 @@ import freechips.rocketchip.unittest._
class AXI4RAMAsyncCrossing(txns: Int)(implicit p: Parameters) extends LazyModule {
val model = LazyModule(new TLRAMModel("AsyncCrossing"))
val ram = LazyModule(new AXI4RAM(AddressSet(0x0, 0x3ff)))
val fuzz = LazyModule(new TLFuzzer(txns))
val toaxi = LazyModule(new TLToAXI4)
val cross = LazyModule(new AXI4AsyncCrossing)
val island = LazyModule(new CrossingWrapper(AsynchronousCrossing(8)))
val ram = island { LazyModule(new AXI4RAM(AddressSet(0x0, 0x3ff))) }
model.node := fuzz.node
toaxi.node := model.node
cross.node := toaxi.node
ram.node := cross.node
ram.node := island.crossAXI4In := toaxi.node
lazy val module = new LazyModuleImp(this) with UnitTestModule {
io.finished := fuzz.module.io.finished
// Shove the RAM into another clock domain
val clocks = Module(new Pow2ClockDivider(2))
ram.module.clock := clocks.io.clock_out
// ... and safely cross AXI42 into it
cross.module.io.in_clock := clock
cross.module.io.in_reset := reset
cross.module.io.out_clock := clocks.io.clock_out
cross.module.io.out_reset := reset
island.module.clock := clocks.io.clock_out
}
}

View File

@ -6,7 +6,7 @@ import Chisel._
import freechips.rocketchip.config.Parameters
import freechips.rocketchip.diplomacy._
import freechips.rocketchip.regmapper._
import freechips.rocketchip.tilelink.{IntSourceNode, IntSourcePortSimple}
import freechips.rocketchip.interrupts.{IntSourceNode, IntSourcePortSimple}
import freechips.rocketchip.util.{HeterogeneousBag, MaskGen}
import scala.math.{min,max}

View File

@ -3,10 +3,11 @@
package freechips.rocketchip.amba
import Chisel._
import freechips.rocketchip.diplomacy.OutwardNodeHandle
import freechips.rocketchip.diplomacy._
package object axi4
{
type AXI4OutwardNode = OutwardNodeHandle[AXI4MasterPortParameters, AXI4SlavePortParameters, AXI4Bundle]
type AXI4AsyncOutwardNode = OutwardNodeHandle[AXI4AsyncMasterPortParameters, AXI4AsyncSlavePortParameters, AXI4AsyncBundle]
type AXI4Node = NodeHandle[AXI4MasterPortParameters, AXI4SlavePortParameters, AXI4Bundle, AXI4MasterPortParameters, AXI4SlavePortParameters, AXI4Bundle]
}

View File

@ -5,18 +5,13 @@ 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._
/** 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 */
abstract class BareCoreplex(implicit p: Parameters) extends LazyModule with BindingScope {
lazy val dts = DTS(bindingTree)

View File

@ -0,0 +1,192 @@
// See LICENSE.SiFive for license details.
package freechips.rocketchip.coreplex
import Chisel._
import freechips.rocketchip.config._
import freechips.rocketchip.diplomacy._
import freechips.rocketchip.tilelink._
import freechips.rocketchip.amba.axi4._
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
private case class CrossingCheck(out: Boolean, source: BaseNode, sink: BaseNode)
trait HasCrossingMethods extends LazyModule with LazyScope
{
// Detect incorrect crossing connectivity
private var checks: List[CrossingCheck] = Nil
private def inside(node: BaseNode) = node.parents.exists(_ eq this)
override def instantiate() {
super.instantiate()
checks.foreach { case CrossingCheck(out, source, sink) =>
source.inputs.foreach { case (syncSource, _) =>
require (inside(syncSource) == out, s"${syncSource.name} must ${if(out)""else"not "}be inside ${name} (wrong .cross direction?)")
}
sink.outputs.foreach { case (syncSink, _) =>
require (inside(syncSink) != out, s"${syncSink.name} must ${if(out)"not "else""}be inside ${name} (wrong .cross direction?)")
}
}
}
// TileLink
def crossTLSyncInOut(out: Boolean)(params: BufferParams = BufferParams.default)(implicit p: Parameters): TLNode = {
val node = this { LazyModule(new TLBuffer(params)).node }
checks = CrossingCheck(out, node, node) :: checks
node
}
def crossTLAsyncInOut(out: Boolean)(depth: Int = 8, sync: Int = 3)(implicit p: Parameters): TLNode = {
def sourceGen = LazyModule(new TLAsyncCrossingSource(sync))
def sinkGen = LazyModule(new TLAsyncCrossingSink(depth, sync))
val source = if (out) this { sourceGen } else sourceGen
val sink = if (out) sinkGen else this { sinkGen }
sink.node :=? source.node
checks = CrossingCheck(out, source.node, sink.node) :: checks
NodeHandle(source.node, sink.node)
}
def crossTLRationalInOut(out: Boolean)(direction: RationalDirection)(implicit p: Parameters): TLNode = {
def sourceGen = LazyModule(new TLRationalCrossingSource)
def sinkGen = LazyModule(new TLRationalCrossingSink(if (out) direction else direction.flip))
val source = if (out) this { sourceGen } else sourceGen
val sink = if (out) sinkGen else this { sinkGen }
sink.node :=? source.node
checks = CrossingCheck(out, source.node, sink.node) :: checks
NodeHandle(source.node, sink.node)
}
def crossTLSyncIn (params: BufferParams = BufferParams.default)(implicit p: Parameters): TLNode = crossTLSyncInOut(false)(params)
def crossTLSyncOut(params: BufferParams = BufferParams.default)(implicit p: Parameters): TLNode = crossTLSyncInOut(true )(params)
def crossTLAsyncIn (depth: Int = 8, sync: Int = 3)(implicit p: Parameters): TLNode = crossTLAsyncInOut(false)(depth, sync)
def crossTLAsyncOut(depth: Int = 8, sync: Int = 3)(implicit p: Parameters): TLNode = crossTLAsyncInOut(true )(depth, sync)
def crossTLRationalIn (direction: RationalDirection)(implicit p: Parameters): TLNode = crossTLRationalInOut(false)(direction)
def crossTLRationalOut(direction: RationalDirection)(implicit p: Parameters): TLNode = crossTLRationalInOut(true )(direction)
def crossTLIn(arg: CoreplexClockCrossing)(implicit p: Parameters): TLNode = arg match {
case x: SynchronousCrossing => crossTLSyncIn(x.params)
case x: AsynchronousCrossing => crossTLAsyncIn(x.depth, x.sync)
case x: RationalCrossing => crossTLRationalIn(x.direction)
}
def crossTLOut(arg: CoreplexClockCrossing)(implicit p: Parameters): TLNode = arg match {
case x: SynchronousCrossing => crossTLSyncOut(x.params)
case x: AsynchronousCrossing => crossTLAsyncOut(x.depth, x.sync)
case x: RationalCrossing => crossTLRationalOut(x.direction)
}
// AXI4
def crossAXI4SyncInOut(out: Boolean)(params: BufferParams = BufferParams.default)(implicit p: Parameters): AXI4Node = {
val node = this { LazyModule(new AXI4Buffer(params)).node }
checks = CrossingCheck(out, node, node) :: checks
node
}
def crossAXI4AsyncInOut(out: Boolean)(depth: Int = 8, sync: Int = 3)(implicit p: Parameters): AXI4Node = {
def sourceGen = LazyModule(new AXI4AsyncCrossingSource(sync))
def sinkGen = LazyModule(new AXI4AsyncCrossingSink(depth, sync))
val source = if (out) this { sourceGen } else sourceGen
val sink = if (out) sinkGen else this { sinkGen }
sink.node :=? source.node
checks = CrossingCheck(out, source.node, sink.node) :: checks
NodeHandle(source.node, sink.node)
}
def crossAXI4SyncIn (params: BufferParams = BufferParams.default)(implicit p: Parameters): AXI4Node = crossAXI4SyncInOut(false)(params)
def crossAXI4SyncOut(params: BufferParams = BufferParams.default)(implicit p: Parameters): AXI4Node = crossAXI4SyncInOut(true )(params)
def crossAXI4AsyncIn (depth: Int = 8, sync: Int = 3)(implicit p: Parameters): AXI4Node = crossAXI4AsyncInOut(false)(depth, sync)
def crossAXI4AsyncOut(depth: Int = 8, sync: Int = 3)(implicit p: Parameters): AXI4Node = crossAXI4AsyncInOut(true )(depth, sync)
def crossAXI4In(arg: CoreplexClockCrossing)(implicit p: Parameters): AXI4Node = arg match {
case x: SynchronousCrossing => crossAXI4SyncIn(x.params)
case x: AsynchronousCrossing => crossAXI4AsyncIn(x.depth, x.sync)
case x: RationalCrossing => throw new IllegalArgumentException("AXI4 Rational crossing unimplemented")
}
def crossAXI4Out(arg: CoreplexClockCrossing)(implicit p: Parameters): AXI4Node = arg match {
case x: SynchronousCrossing => crossAXI4SyncOut(x.params)
case x: AsynchronousCrossing => crossAXI4AsyncOut(x.depth, x.sync)
case x: RationalCrossing => throw new IllegalArgumentException("AXI4 Rational crossing unimplemented")
}
// Interrupts
def crossIntSyncInOut(out: Boolean)(alreadyRegistered: Boolean = false)(implicit p: Parameters): IntNode = {
def sourceGen = LazyModule(new IntSyncCrossingSource(alreadyRegistered))
def sinkGen = LazyModule(new IntSyncCrossingSink(0))
val source = if (out) this { sourceGen } else sourceGen
val sink = if (out) sinkGen else this { sinkGen }
sink.node :=? source.node
checks = CrossingCheck(out, source.node, sink.node) :: checks
NodeHandle(source.node, sink.node)
}
def crossIntAsyncInOut(out: Boolean)(sync: Int = 3, alreadyRegistered: Boolean = false)(implicit p: Parameters): IntNode = {
def sourceGen = LazyModule(new IntSyncCrossingSource(alreadyRegistered))
def sinkGen = LazyModule(new IntSyncCrossingSink(sync))
val source = if (out) this { sourceGen } else sourceGen
val sink = if (out) sinkGen else this { sinkGen }
sink.node :=? source.node
checks = CrossingCheck(out, source.node, sink.node) :: checks
NodeHandle(source.node, sink.node)
}
def crossIntRationalInOut(out: Boolean)(alreadyRegistered: Boolean = false)(implicit p: Parameters): IntNode = {
def sourceGen = LazyModule(new IntSyncCrossingSource(alreadyRegistered))
def sinkGen = LazyModule(new IntSyncCrossingSink(1))
val source = if (out) this { sourceGen } else sourceGen
val sink = if (out) sinkGen else this { sinkGen }
sink.node :=? source.node
checks = CrossingCheck(out, source.node, sink.node) :: checks
NodeHandle(source.node, sink.node)
}
def crossIntSyncIn (alreadyRegistered: Boolean = false)(implicit p: Parameters): IntNode = crossIntSyncInOut(false)(alreadyRegistered)
def crossIntSyncOut(alreadyRegistered: Boolean = false)(implicit p: Parameters): IntNode = crossIntSyncInOut(true )(alreadyRegistered)
def crossIntAsyncIn (sync: Int = 3, alreadyRegistered: Boolean = false)(implicit p: Parameters): IntNode = crossIntAsyncInOut(false)(sync, alreadyRegistered)
def crossIntAsyncOut(sync: Int = 3, alreadyRegistered: Boolean = false)(implicit p: Parameters): IntNode = crossIntAsyncInOut(true )(sync, alreadyRegistered)
def crossIntRationalIn (alreadyRegistered: Boolean = false)(implicit p: Parameters): IntNode = crossIntRationalInOut(false)(alreadyRegistered)
def crossIntRationalOut(alreadyRegistered: Boolean = false)(implicit p: Parameters): IntNode = crossIntRationalInOut(true )(alreadyRegistered)
def crossIntIn(arg: CoreplexClockCrossing, alreadyRegistered: Boolean)(implicit p: Parameters): IntNode = arg match {
case x: SynchronousCrossing => crossIntSyncIn(alreadyRegistered)
case x: AsynchronousCrossing => crossIntAsyncIn(x.sync, alreadyRegistered)
case x: RationalCrossing => crossIntRationalIn(alreadyRegistered)
}
def crossIntOut(arg: CoreplexClockCrossing, alreadyRegistered: Boolean)(implicit p: Parameters): IntNode = arg match {
case x: SynchronousCrossing => crossIntSyncOut(alreadyRegistered)
case x: AsynchronousCrossing => crossIntAsyncOut(x.sync, alreadyRegistered)
case x: RationalCrossing => crossIntRationalOut(alreadyRegistered)
}
def crossIntIn (arg: CoreplexClockCrossing)(implicit p: Parameters): IntNode = crossIntIn (arg, false)
def crossIntOut(arg: CoreplexClockCrossing)(implicit p: Parameters): IntNode = crossIntOut(arg, false)
}
trait HasCrossing extends HasCrossingMethods
{
this: LazyModule =>
val crossing: CoreplexClockCrossing
def crossTLIn (implicit p: Parameters): TLNode = crossTLIn (crossing)
def crossTLOut (implicit p: Parameters): TLNode = crossTLOut (crossing)
def crossAXI4In (implicit p: Parameters): AXI4Node= crossAXI4In (crossing)
def crossAXI4Out(implicit p: Parameters): AXI4Node= crossAXI4Out(crossing)
def crossIntIn (implicit p: Parameters): IntNode = crossIntIn (crossing)
def crossIntOut (implicit p: Parameters): IntNode = crossIntOut (crossing)
def crossIntIn (alreadyRegistered: Boolean)(implicit p: Parameters): IntNode = crossIntIn (crossing, alreadyRegistered)
def crossIntOut(alreadyRegistered: Boolean)(implicit p: Parameters): IntNode = crossIntOut(crossing, alreadyRegistered)
}
class CrossingWrapper(val crossing: CoreplexClockCrossing)(implicit p: Parameters) extends SimpleLazyModule with HasCrossing

View File

@ -28,16 +28,12 @@ class FrontBus(params: FrontBusParams)(implicit p: Parameters) extends TLBusWrap
master_fixer.node :=* master_buffer.node
inwardNode :=* master_fixer.node
def fromSyncPorts(addBuffers: Int = 0, name: Option[String] = None): TLInwardNode = {
val (in, out) = bufferChain(addBuffers, name)
master_buffer.node :=* out
in
def fromSyncPorts(addBuffers: Int = 0, name: Option[String] = None): TLInwardNode = SourceCardinality { implicit p =>
TLBuffer.chain(addBuffers).foldLeft(master_buffer.node:TLInwardNode)(_ :=? _)
}
def fromSyncMasters(addBuffers: Int = 0, name: Option[String] = None): TLInwardNode = {
val (in, out) = bufferChain(addBuffers, name)
master_buffer.node :=* out
in
def fromSyncMasters(addBuffers: Int = 0, name: Option[String] = None): TLInwardNode = SourceCardinality { implicit p =>
TLBuffer.chain(addBuffers).foldLeft(master_buffer.node:TLInwardNode)(_ :=? _)
}
def fromCoherentChip: TLInwardNode = inwardNode

View File

@ -5,7 +5,7 @@ package freechips.rocketchip.coreplex
import Chisel._
import freechips.rocketchip.config.{Field, Parameters}
import freechips.rocketchip.diplomacy._
import freechips.rocketchip.tilelink._
import freechips.rocketchip.interrupts._
/** Collects interrupts from internal and external devices and feeds them into the PLIC */
class InterruptBusWrapper(implicit p: Parameters) {

View File

@ -31,35 +31,23 @@ class PeripheryBus(params: PeripheryBusParams)(implicit p: Parameters) extends T
TLFragmenter(params.beatBytes, maxXferBytes)(outwardBufNode)
}
def toSyncSlaves(adapt: () => TLNodeChain, name: Option[String]): TLOutwardNode = SinkCardinality { implicit p =>
val adapters = adapt()
adapters.in :=? outwardBufNode
adapters.out
}
def toAsyncSlaves(sync: Int, adapt: () => TLNodeChain, name: Option[String]): TLAsyncOutwardNode = SinkCardinality { implicit p =>
val adapters = adapt()
val source = LazyModule(new TLAsyncCrossingSource(sync))
name.foreach{ n => source.suggestName(s"${busName}_${n}_TLAsyncCrossingSource")}
adapters.in :=? outwardNode
source.node :=? adapters.out
source.node
}
def toRationalSlaves(adapt: () => TLNodeChain, name: Option[String]): TLRationalOutwardNode = SinkCardinality { implicit p =>
val adapters = adapt()
val source = LazyModule(new TLRationalCrossingSource())
name.foreach{ n => source.suggestName(s"${busName}_${n}_TLRationalCrossingSource")}
adapters.in :=? outwardNode
source.node :=? adapters.out
source.node
}
val fromSystemBus: TLInwardNode = {
val atomics = LazyModule(new TLAtomicAutomata(arithmetic = params.arithmetic))
inwardBufNode := atomics.node
atomics.node
}
def toTile(name: Option[String] = None)(gen: Parameters => TLInwardNode) {
this {
LazyScope(s"${busName}ToTile${name.getOrElse("")}") {
SinkCardinality { implicit p =>
FlipRendering { implicit p =>
gen(p) :*= outwardNode
}
}
}
}
}
}
/** Provides buses that serve as attachment points,

View File

@ -3,67 +3,54 @@
package freechips.rocketchip.coreplex
import Chisel._
import chisel3.internal.sourceinfo.SourceInfo
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.interrupts._
import freechips.rocketchip.util._
case class TLNodeChain(in: TLInwardNode, out: TLOutwardNode)
// TODO: how specific are these to RocketTiles?
case class TileMasterPortParams(
addBuffers: Int = 0,
blockerCtrlAddr: Option[BigInt] = None,
cork: Option[Boolean] = None) {
def adapterChain(coreplex: HasPeripheryBus)
(implicit p: Parameters): () => TLNodeChain = {
val blockerParams = blockerCtrlAddr.map(BasicBusBlockerParams(_, coreplex.pbus.beatBytes, coreplex.sbus.beatBytes, deadlock = true))
def adapt(coreplex: HasPeripheryBus)
(masterNode: TLOutwardNode)
(implicit p: Parameters, sourceInfo: SourceInfo): TLOutwardNode = {
val tile_master_cork = cork.map(u => (LazyModule(new TLCacheCork(unsafe = u))))
val tile_master_blocker = blockerParams.map(bp => LazyModule(new BasicBusBlocker(bp)))
val tile_master_blocker =
blockerCtrlAddr
.map(BasicBusBlockerParams(_, coreplex.pbus.beatBytes, coreplex.sbus.beatBytes, deadlock = true))
.map(bp => LazyModule(new BasicBusBlocker(bp)))
val tile_master_fixer = LazyModule(new TLFIFOFixer(TLFIFOFixer.allUncacheable))
val tile_master_buffer = LazyModule(new TLBufferChain(addBuffers))
tile_master_blocker.foreach { _.controlNode := coreplex.pbus.toVariableWidthSlaves }
val nodes = List(
Some(tile_master_buffer.node),
Some(tile_master_fixer.node),
tile_master_blocker.map(_.node),
tile_master_cork.map(_.node)
).flatMap(b=>b)
nodes.init zip nodes.tail foreach { case(front, back) => front :=* back }
() => TLNodeChain(in = nodes.last, out = nodes.head)
(Seq(tile_master_fixer.node) ++ TLBuffer.chain(addBuffers)
++ tile_master_blocker.map(_.node) ++ tile_master_cork.map(_.node))
.foldRight(masterNode)(_ :=* _)
}
}
case class TileSlavePortParams(
addBuffers: Int = 0,
blockerCtrlAddr: Option[BigInt] = None) {
def adapterChain(coreplex: HasPeripheryBus)
(implicit p: Parameters): () => TLNodeChain = {
val blockerParams = blockerCtrlAddr.map(BasicBusBlockerParams(_, coreplex.pbus.beatBytes, coreplex.sbus.beatBytes))
val tile_slave_blocker = blockerParams.map(bp => LazyModule(new BasicBusBlocker(bp)))
val tile_slave_buffer = LazyModule(new TLBufferChain(addBuffers))
def adapt(coreplex: HasPeripheryBus)
(slaveNode: TLInwardNode)
(implicit p: Parameters, sourceInfo: SourceInfo): TLInwardNode = {
val tile_slave_blocker =
blockerCtrlAddr
.map(BasicBusBlockerParams(_, coreplex.pbus.beatBytes, coreplex.sbus.beatBytes))
.map(bp => LazyModule(new BasicBusBlocker(bp)))
tile_slave_blocker.foreach { _.controlNode := coreplex.pbus.toVariableWidthSlaves }
val nodes = List(
Some(tile_slave_buffer.node),
tile_slave_blocker.map(_.node)
).flatMap(b=>b)
nodes.init zip nodes.tail foreach { case(front, back) => front :=* back }
() => TLNodeChain(in = nodes.last, out = nodes.head)
(Seq() ++ tile_slave_blocker.map(_.node) ++ TLBuffer.chain(addBuffers))
.foldLeft(slaveNode)(_ :*= _)
}
}
@ -95,67 +82,55 @@ trait HasRocketTiles extends HasTiles
case NumRocketTiles => crossingParams
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,
// 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 pWithExtra = p.alterPartial {
case TileKey => tp
case BuildRoCC => tp.rocc
case SharedMemoryTLEdge => sharedMemoryTLEdge
case RocketCrossingKey => List(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 {
case TileKey => tp
case BuildRoCC => tp.rocc
case SharedMemoryTLEdge => sharedMemoryTLEdge
case RocketCrossingKey => List(crossing)
})
).suggestName(tp.name)
val wrapper = crossing.crossingType match {
case SynchronousCrossing(params) => {
val wrapper = LazyModule(new SyncRocketTile(tp)(pWithExtra))
sbus.fromSyncTiles(params, crossing.master.adapterChain(this), tp.name) :=* wrapper.masterNode
FlipRendering { implicit p => wrapper.slaveNode :*= pbus.toSyncSlaves(crossing.slave.adapterChain(this), tp.name) }
wrapper
}
case AsynchronousCrossing(depth, sync) => {
val wrapper = LazyModule(new AsyncRocketTile(tp)(pWithExtra))
sbus.fromAsyncTiles(depth, sync, crossing.master.adapterChain(this), tp.name) :=* wrapper.masterNode
FlipRendering { implicit p => wrapper.slaveNode :*= pbus.toAsyncSlaves(sync, crossing.slave.adapterChain(this), tp.name) }
wrapper
}
case RationalCrossing(direction) => {
val wrapper = LazyModule(new RationalRocketTile(tp)(pWithExtra))
sbus.fromRationalTiles(direction, crossing.master.adapterChain(this), tp.name) :=* wrapper.masterNode
FlipRendering { implicit p => wrapper.slaveNode :*= pbus.toRationalSlaves(crossing.slave.adapterChain(this), tp.name) }
wrapper
}
}
tp.name.foreach(wrapper.suggestName) // Try to stabilize this name for downstream tools
// 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) }
// 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.suggestName("asyncIntXbar")
asyncIntXbar.intnode := debug.intnode // debug
wrapper.asyncIntNode := asyncIntXbar.intnode
// 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) }
val periphIntXbar = LazyModule(new IntXbar)
periphIntXbar.suggestName("periphIntXbar")
periphIntXbar.intnode := clint.intnode // msip+mtip
periphIntXbar.intnode := plic.intnode // meip
if (tp.core.useVM) periphIntXbar.intnode := plic.intnode // seip
wrapper.periphIntNode := periphIntXbar.intnode
// 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.
val coreIntXbar = LazyModule(new IntXbar)
coreIntXbar.suggestName("coreIntXbar")
lip.foreach { coreIntXbar.intnode := _ } // lip
wrapper.coreIntNode := coreIntXbar.intnode
wrapper.intXbar.intnode := wrapper { IntSyncCrossingSink(3) } := debug.intnode // 1. always async crossign
wrapper.intOutputNode.foreach { case int =>
val rocketIntXing = LazyModule(new IntXing(wrapper.outputInterruptXingLatency))
FlipRendering { implicit p => rocketIntXing.intnode := int }
plic.intnode := rocketIntXing.intnode
// 2. clint+plic conditionak crossing
val periphIntNode = SourceCardinality { implicit p => wrapper.intXbar.intnode :=? wrapper.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
// From core to PLIC
wrapper.rocket.intOutputNode.foreach { i => // 4. conditional crossing
FlipRendering { implicit p => SourceCardinality { implicit p =>
plic.intnode :=? wrapper.crossIntOut :=? i
} }
}
wrapper

View File

@ -39,9 +39,7 @@ class SystemBus(params: SystemBusParams)(implicit p: Parameters) extends TLBusWr
def toSplitSlaves: TLOutwardNode = outwardSplitNode
def toPeripheryBus(addBuffers: Int = 0): TLOutwardNode = {
val (in, out) = bufferChain(addBuffers, name = Some("pbus"))
in := pbus_fixer.node
out
TLBuffer.chain(addBuffers).foldRight(pbus_fixer.node:TLOutwardNode)(_ := _)
}
val toMemoryBus: TLOutwardNode = outwardNode
@ -52,34 +50,14 @@ class SystemBus(params: SystemBusParams)(implicit p: Parameters) extends TLBusWr
def fromFrontBus: TLInwardNode = master_splitter.node
def fromSyncTiles(params: BufferParams, adapt: () => TLNodeChain, name: Option[String] = None): TLInwardNode = {
val adapters = adapt() // wanted to be called inside SystemBus scope
val tile_sink = LazyModule(new TLBuffer(params))
name.foreach { n => tile_sink.suggestName(s"${busName}_${n}_TLBuffer") }
adapters.in :=* tile_sink.node
master_splitter.node :=* adapters.out
tile_sink.node
}
def fromRationalTiles(dir: RationalDirection, adapt: () => TLNodeChain, name: Option[String] = None): TLRationalInwardNode = {
val adapters = adapt() // wanted to be called inside SystemBus scope
val tile_sink = LazyModule(new TLRationalCrossingSink(direction = dir))
name.foreach { n => tile_sink.suggestName(s"${busName}_${n}_TLRationalCrossingSink") }
adapters.in :=* tile_sink.node
master_splitter.node :=* adapters.out
tile_sink.node
}
def fromAsyncTiles(depth: Int, sync: Int, adapt: () => TLNodeChain, name: Option[String] = None): TLAsyncInwardNode = {
val adapters = adapt() // wanted to be called inside SystemBus scope
val tile_sink = LazyModule(new TLAsyncCrossingSink(depth, sync))
name.foreach { n => tile_sink.suggestName(s"${busName}_${n}_TLAsyncCrossingSink") }
adapters.in :=* tile_sink.node
master_splitter.node :=* adapters.out
tile_sink.node
def fromTile(name: Option[String])(gen: Parameters => TLOutwardNode) {
this {
LazyScope(s"${busName}FromTile${name.getOrElse("")}") {
SourceCardinality { implicit p =>
master_splitter.node :=* gen(p)
}
}
}
}
def fromSyncPorts(params: BufferParams = BufferParams.default, name: Option[String] = None): TLInwardNode = {

View File

@ -0,0 +1,12 @@
// See LICENSE.SiFive for license details.
package freechips.rocketchip
import freechips.rocketchip.tilelink.TLOutwardNode
import freechips.rocketchip.interrupts.IntOutwardNode
package object coreplex
{
implicit class TLCrossableNode(val node: TLOutwardNode)
implicit class IntCrossableNode(val node: IntOutwardNode)
}

View File

@ -9,6 +9,7 @@ import freechips.rocketchip.regmapper._
import freechips.rocketchip.rocket.Instructions
import freechips.rocketchip.tile.XLen
import freechips.rocketchip.tilelink._
import freechips.rocketchip.interrupts._
import freechips.rocketchip.util._
/** Constant values used by both Debug Bus Response & Request
@ -392,7 +393,7 @@ class TLDebugModuleOuterAsync(device: Device)(implicit p: Parameters) extends La
val dmiXbar = LazyModule (new TLXbar())
val dmOuter = LazyModule( new TLDebugModuleOuter(device))
val intnode = dmOuter.intnode
val intnode: IntSyncOutwardNode = IntSyncCrossingSource(alreadyRegistered = true) :*= dmOuter.intnode
val dmiInnerNode = TLAsyncCrossingSource()(dmiXbar.node)
@ -401,7 +402,7 @@ class TLDebugModuleOuterAsync(device: Device)(implicit p: Parameters) extends La
lazy val module = new LazyModuleImp(this) {
val nComponents = intnode.out.size
val nComponents = dmOuter.intnode.edges.out.size
val io = IO(new Bundle {
val dmi = new DMIIO()(p).flip()
@ -1039,7 +1040,7 @@ class TLDebugModule(implicit p: Parameters) extends LazyModule {
}
val dmOuter = LazyModule(new TLDebugModuleOuterAsync(device)(p))
val dmInner = LazyModule(new TLDebugModuleInnerAsync(device, () => {intnode.edges.out.size})(p))
val dmInner = LazyModule(new TLDebugModuleInnerAsync(device, () => {dmOuter.dmOuter.intnode.edges.out.size})(p))
val node = dmInner.tlNode
val intnode = dmOuter.intnode
@ -1047,7 +1048,7 @@ class TLDebugModule(implicit p: Parameters) extends LazyModule {
dmInner.dmiNode := dmOuter.dmiInnerNode
lazy val module = new LazyModuleImp(this) {
val nComponents = intnode.out.size
val nComponents = dmOuter.dmOuter.intnode.edges.out.size
val io = IO(new Bundle {
val ctrl = new DebugCtrlBundle(nComponents)

View File

@ -9,6 +9,7 @@ import freechips.rocketchip.diplomacy._
import freechips.rocketchip.regmapper._
import freechips.rocketchip.tile.XLen
import freechips.rocketchip.tilelink._
import freechips.rocketchip.interrupts._
import freechips.rocketchip.util._
import scala.math.{min,max}

View File

@ -10,6 +10,7 @@ import freechips.rocketchip.diplomacy._
import freechips.rocketchip.regmapper._
import freechips.rocketchip.tile.XLen
import freechips.rocketchip.tilelink._
import freechips.rocketchip.interrupts._
import freechips.rocketchip.util._
import scala.math.min

View File

@ -11,17 +11,26 @@ import scala.util.matching._
abstract class LazyModule()(implicit val p: Parameters)
{
protected[diplomacy] var bindings = List[() => Unit]()
protected[diplomacy] var children = List[LazyModule]()
protected[diplomacy] var nodes = List[BaseNode]()
protected[diplomacy] var info: SourceInfo = UnlocatableSourceInfo
protected[diplomacy] val parent = LazyModule.scope
def parents: Seq[LazyModule] = parent match {
case None => Nil
case Some(x) => x +: x.parents
}
LazyModule.scope = Some(this)
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
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 =
getClass.getMethods.filter { m =>
@ -54,6 +63,7 @@ abstract class LazyModule()(implicit val p: Parameters)
def name = valName.getOrElse(className)
def line = sourceLine(info)
def instantiate() { } // a hook for running things in module scope (after children exist, but before dangles+auto exists)
def module: LazyModuleImpLike
def omitGraphML: Boolean = !nodes.exists(!_.omitGraphML) && !children.exists(!_.omitGraphML)
@ -154,6 +164,7 @@ sealed trait LazyModuleImpLike extends BaseModule
implicit val sourceInfo = c.info
Module(c.module).dangles
}
wrapper.instantiate()
val nodeDangles = wrapper.nodes.reverse.flatMap(_.instantiate())
val allDangles = nodeDangles ++ childDangles
val pairing = SortedMap(allDangles.groupBy(_.source).toSeq:_*)
@ -168,7 +179,6 @@ sealed trait LazyModuleImpLike extends BaseModule
if (d.flipped) { d.data <> io } else { io <> d.data }
d.copy(data = io, name = wrapper.valName.getOrElse("anon") + "_" + d.name)
}
wrapper.bindings.reverse.foreach { f => f () }
(auto, dangles)
}
}

View File

@ -98,6 +98,8 @@ abstract class BaseNode(implicit val valName: ValName)
def omitGraphML = outputs.isEmpty && inputs.isEmpty
lazy val nodedebugstring: String = ""
def parents: Seq[LazyModule] = lazyModule +: lazyModule.parents
def wirePrefix = {
val camelCase = "([a-z])([A-Z])".r
val decamel = camelCase.replaceAllIn(valName.name, _ match { case camelCase(l, h) => l + "_" + h })
@ -108,8 +110,8 @@ abstract class BaseNode(implicit val valName: ValName)
protected[diplomacy] def gci: Option[BaseNode] // greatest common inner
protected[diplomacy] def gco: Option[BaseNode] // greatest common outer
protected[diplomacy] def inputs: Seq[(BaseNode, RenderedEdge)]
protected[diplomacy] def outputs: Seq[(BaseNode, RenderedEdge)]
def inputs: Seq[(BaseNode, RenderedEdge)]
def outputs: Seq[(BaseNode, RenderedEdge)]
}
object BaseNode
@ -117,22 +119,53 @@ object BaseNode
protected[diplomacy] var serial = 0
}
// !!! rename the nodes we bind?
case class NodeHandle[DI, UI, BI <: Data, DO, UO, BO <: Data]
trait NoHandle
case object NoHandleObject extends NoHandle
trait NodeHandle[DI, UI, BI <: Data, DO, UO, BO <: Data]
extends InwardNodeHandle[DI, UI, BI] with OutwardNodeHandle[DO, UO, BO]
{
// connecting two full nodes => full node
override def := [DX, UX, BX <: Data](h: NodeHandle[DX, UX, BX, DI, UI, BI])(implicit p: Parameters, sourceInfo: SourceInfo): NodeHandle[DX, UX, BX, DO, UO, BO] = { bind(h, BIND_ONCE); NodeHandle(h, this) }
override def :*= [DX, UX, BX <: Data](h: NodeHandle[DX, UX, BX, DI, UI, BI])(implicit p: Parameters, sourceInfo: SourceInfo): NodeHandle[DX, UX, BX, DO, UO, BO] = { bind(h, BIND_STAR); NodeHandle(h, this) }
override def :=* [DX, UX, BX <: Data](h: NodeHandle[DX, UX, BX, DI, UI, BI])(implicit p: Parameters, sourceInfo: SourceInfo): NodeHandle[DX, UX, BX, DO, UO, BO] = { bind(h, BIND_QUERY); NodeHandle(h, this) }
override def :=? [DX, UX, BX <: Data](h: NodeHandle[DX, UX, BX, DI, UI, BI])(implicit p: Parameters, sourceInfo: SourceInfo): NodeHandle[DX, UX, BX, DO, UO, BO] = { bind(h, p(CardinalityInferenceDirectionKey)); NodeHandle(h, this) }
// connecting a full node with an output => an output
override def := (h: OutwardNodeHandle[DI, UI, BI])(implicit p: Parameters, sourceInfo: SourceInfo): OutwardNodeHandle[DO, UO, BO] = { bind(h, BIND_ONCE); this }
override def :*= (h: OutwardNodeHandle[DI, UI, BI])(implicit p: Parameters, sourceInfo: SourceInfo): OutwardNodeHandle[DO, UO, BO] = { bind(h, BIND_STAR); this }
override def :=* (h: OutwardNodeHandle[DI, UI, BI])(implicit p: Parameters, sourceInfo: SourceInfo): OutwardNodeHandle[DO, UO, BO] = { bind(h, BIND_QUERY); this }
override def :=? (h: OutwardNodeHandle[DI, UI, BI])(implicit p: Parameters, sourceInfo: SourceInfo): OutwardNodeHandle[DO, UO, BO] = { bind(h, p(CardinalityInferenceDirectionKey)); this }
}
object NodeHandle
{
def apply[DI, UI, BI <: Data, DO, UO, BO <: Data](i: InwardNodeHandle[DI, UI, BI], o: OutwardNodeHandle[DO, UO, BO]) = NodeHandlePair(i, o)
}
case class NodeHandlePair[DI, UI, BI <: Data, DO, UO, BO <: Data]
(inwardHandle: InwardNodeHandle[DI, UI, BI], outwardHandle: OutwardNodeHandle[DO, UO, BO])
extends Object with InwardNodeHandle[DI, UI, BI] with OutwardNodeHandle[DO, UO, BO]
extends NodeHandle[DI, UI, BI, DO, UO, BO]
{
val inward = inwardHandle.inward
val outward = outwardHandle.outward
}
trait InwardNodeHandle[DI, UI, BI <: Data]
trait InwardNodeHandle[DI, UI, BI <: Data] extends NoHandle
{
protected[diplomacy] val inward: InwardNode[DI, UI, BI]
def := (h: OutwardNodeHandle[DI, UI, BI])(implicit p: Parameters, sourceInfo: SourceInfo) { inward.:=(h)(p, sourceInfo) }
def :*= (h: OutwardNodeHandle[DI, UI, BI])(implicit p: Parameters, sourceInfo: SourceInfo) { inward.:*=(h)(p, sourceInfo) }
def :=* (h: OutwardNodeHandle[DI, UI, BI])(implicit p: Parameters, sourceInfo: SourceInfo) { inward.:=*(h)(p, sourceInfo) }
def :=? (h: OutwardNodeHandle[DI, UI, BI])(implicit p: Parameters, sourceInfo: SourceInfo) { inward.:=?(h)(p, sourceInfo) }
def inward: InwardNode[DI, UI, BI]
def parentsIn: Seq[LazyModule] = inward.parents
def bind(h: OutwardNodeHandle[DI, UI, BI], binding: NodeBinding)(implicit p: Parameters, sourceInfo: SourceInfo): Unit = inward.bind(h.outward, binding)
// connecting an input node with a full nodes => an input node
def := [DX, UX, BX <: Data](h: NodeHandle[DX, UX, BX, DI, UI, BI])(implicit p: Parameters, sourceInfo: SourceInfo): InwardNodeHandle[DX, UX, BX] = { bind(h, BIND_ONCE); h }
def :*= [DX, UX, BX <: Data](h: NodeHandle[DX, UX, BX, DI, UI, BI])(implicit p: Parameters, sourceInfo: SourceInfo): InwardNodeHandle[DX, UX, BX] = { bind(h, BIND_STAR); h }
def :=* [DX, UX, BX <: Data](h: NodeHandle[DX, UX, BX, DI, UI, BI])(implicit p: Parameters, sourceInfo: SourceInfo): InwardNodeHandle[DX, UX, BX] = { bind(h, BIND_QUERY); h }
def :=? [DX, UX, BX <: Data](h: NodeHandle[DX, UX, BX, DI, UI, BI])(implicit p: Parameters, sourceInfo: SourceInfo): InwardNodeHandle[DX, UX, BX] = { bind(h, p(CardinalityInferenceDirectionKey)); h }
// connecting input node with output node => no node
def := (h: OutwardNodeHandle[DI, UI, BI])(implicit p: Parameters, sourceInfo: SourceInfo): NoHandle = { bind(h, BIND_ONCE); NoHandleObject }
def :*= (h: OutwardNodeHandle[DI, UI, BI])(implicit p: Parameters, sourceInfo: SourceInfo): NoHandle = { bind(h, BIND_STAR); NoHandleObject }
def :=* (h: OutwardNodeHandle[DI, UI, BI])(implicit p: Parameters, sourceInfo: SourceInfo): NoHandle = { bind(h, BIND_QUERY); NoHandleObject }
def :=? (h: OutwardNodeHandle[DI, UI, BI])(implicit p: Parameters, sourceInfo: SourceInfo): NoHandle = { bind(h, p(CardinalityInferenceDirectionKey)); NoHandleObject }
}
sealed trait NodeBinding
@ -140,9 +173,18 @@ case object BIND_ONCE extends NodeBinding
case object BIND_QUERY extends NodeBinding
case object BIND_STAR extends NodeBinding
object NodeBinding
{
implicit def apply(card: CardinalityInferenceDirection.T): NodeBinding = card match {
case CardinalityInferenceDirection.SOURCE_TO_SINK => BIND_QUERY
case CardinalityInferenceDirection.SINK_TO_SOURCE => BIND_STAR
case CardinalityInferenceDirection.NO_INFERENCE => BIND_ONCE
}
}
trait InwardNode[DI, UI, BI <: Data] extends BaseNode with InwardNodeHandle[DI, UI, BI]
{
protected[diplomacy] val inward = this
val inward = this
protected[diplomacy] val numPI: Range.Inclusive
require (!numPI.isEmpty, s"No number of inputs would be acceptable to ${name}${lazyModule.line}")
@ -165,16 +207,19 @@ trait InwardNode[DI, UI, BI <: Data] extends BaseNode with InwardNodeHandle[DI,
protected[diplomacy] val iStar: Int
protected[diplomacy] val iPortMapping: Seq[(Int, Int)]
protected[diplomacy] val iParams: Seq[UI]
protected[diplomacy] def bind(h: OutwardNode[DI, UI, BI], binding: NodeBinding)(implicit p: Parameters, sourceInfo: SourceInfo): Unit
}
trait OutwardNodeHandle[DO, UO, BO <: Data]
trait OutwardNodeHandle[DO, UO, BO <: Data] extends NoHandle
{
protected[diplomacy] val outward: OutwardNode[DO, UO, BO]
def outward: OutwardNode[DO, UO, BO]
def parentsOut: Seq[LazyModule] = outward.parents
}
trait OutwardNode[DO, UO, BO <: Data] extends BaseNode with OutwardNodeHandle[DO, UO, BO]
{
protected[diplomacy] val outward = this
val outward = this
protected[diplomacy] val numPO: Range.Inclusive
require (!numPO.isEmpty, s"No number of outputs would be acceptable to ${name}${lazyModule.line}")
@ -211,7 +256,7 @@ sealed abstract class MixedNode[DI, UI, EI, BI <: Data, DO, UO, EO, BO <: Data](
protected[diplomacy] val numPO: Range.Inclusive,
protected[diplomacy] val numPI: Range.Inclusive)(
implicit valName: ValName)
extends BaseNode with InwardNode[DI, UI, BI] with OutwardNode[DO, UO, BO]
extends BaseNode with NodeHandle[DI, UI, BI, DO, UO, BO] with InwardNode[DI, UI, BI] with OutwardNode[DO, UO, BO]
{
protected[diplomacy] def resolveStar(iKnown: Int, oKnown: Int, iStar: Int, oStar: Int): (Int, Int)
protected[diplomacy] def mapParamsD(n: Int, p: Seq[DI]): Seq[DO]
@ -337,9 +382,9 @@ sealed abstract class MixedNode[DI, UI, EI, BI <: Data, DO, UO, EO, BO <: Data](
}
// connects the outward part of a node with the inward part of this node
private def bind(h: OutwardNodeHandle[DI, UI, BI], binding: NodeBinding)(implicit p: Parameters, sourceInfo: SourceInfo) {
protected[diplomacy] def bind(h: OutwardNode[DI, UI, BI], binding: NodeBinding)(implicit p: Parameters, sourceInfo: SourceInfo) {
val x = this // x := y
val y = h.outward
val y = h
val info = sourceLine(sourceInfo, " at ", "")
val i = x.iPushed
val o = y.oPushed
@ -350,23 +395,12 @@ sealed abstract class MixedNode[DI, UI, EI, BI <: Data, DO, UO, EO, BO <: Data](
x.iPush(o, y, binding)
}
override def := (h: OutwardNodeHandle[DI, UI, BI])(implicit p: Parameters, sourceInfo: SourceInfo) = bind(h, BIND_ONCE)
override def :*= (h: OutwardNodeHandle[DI, UI, BI])(implicit p: Parameters, sourceInfo: SourceInfo) = bind(h, BIND_STAR)
override def :=* (h: OutwardNodeHandle[DI, UI, BI])(implicit p: Parameters, sourceInfo: SourceInfo) = bind(h, BIND_QUERY)
override def :=? (h: OutwardNodeHandle[DI, UI, BI])(implicit p: Parameters, sourceInfo: SourceInfo) = {
p(CardinalityInferenceDirectionKey) match {
case CardinalityInferenceDirection.SOURCE_TO_SINK => this :=* h
case CardinalityInferenceDirection.SINK_TO_SOURCE => this :*= h
case CardinalityInferenceDirection.NO_INFERENCE => this := h
}
}
// meta-data for printing the node graph
protected[diplomacy] def inputs = (iPorts zip edgesIn) map { case ((_, n, p, _), e) =>
def inputs = (iPorts zip edgesIn) map { case ((_, n, p, _), e) =>
val re = inner.render(e)
(n, re.copy(flipped = re.flipped != p(RenderFlipped)))
}
protected[diplomacy] def outputs = oPorts map { case (i, n, _, _) => (n, n.inputs(i)._2) }
def outputs = oPorts map { case (i, n, _, _) => (n, n.inputs(i)._2) }
}
abstract class MixedCustomNode[DI, UI, EI, BI <: Data, DO, UO, EO, BO <: Data](

View File

@ -25,8 +25,8 @@ class GroundTestCoreplex(implicit p: Parameters) extends BaseCoreplex
})
)}
tiles.flatMap(_.dcacheOpt).foreach {
sbus.fromSyncTiles(BufferParams.default, TileMasterPortParams().adapterChain(this)) :=* _.node
tiles.flatMap(_.dcacheOpt).foreach { dc =>
sbus.fromTile(None) { implicit p => TileMasterPortParams(addBuffers = 1).adapt(this)(dc.node) }
}
val pbusRAM = LazyModule(new TLRAM(AddressSet(testRamAddr, 0xffff), true, false, pbus.beatBytes))

View File

@ -0,0 +1,12 @@
// See LICENSE.SiFive for license details.
package freechips.rocketchip.interrupts
import Chisel._
import freechips.rocketchip.diplomacy._
import freechips.rocketchip.util._
class SyncInterrupts(params: IntEdge) extends GenericParameterizedBundle(params)
{
val sync = Vec(params.source.num, Bool())
}

View File

@ -0,0 +1,58 @@
// See LICENSE.SiFive for license details.
package freechips.rocketchip.interrupts
import Chisel._
import freechips.rocketchip.config.Parameters
import freechips.rocketchip.util.SynchronizerShiftReg
import freechips.rocketchip.diplomacy._
@deprecated("IntXing does not ensure interrupt source is glitch free. Use IntSyncSource and IntSyncSink", "rocket-chip 1.2")
class IntXing(sync: Int = 3)(implicit p: Parameters) extends LazyModule
{
val intnode = IntAdapterNode()
lazy val module = new LazyModuleImp(this) {
(intnode.in zip intnode.out) foreach { case ((in, _), (out, _)) =>
out := SynchronizerShiftReg(in, sync)
}
}
}
object IntSyncCrossingSource
{
def apply(alreadyRegistered: Boolean = false)(implicit p: Parameters) = LazyModule(new IntSyncCrossingSource(alreadyRegistered)).node
}
class IntSyncCrossingSource(alreadyRegistered: Boolean = false)(implicit p: Parameters) extends LazyModule
{
val node = IntSyncSourceNode(alreadyRegistered)
lazy val module = new LazyModuleImp(this) {
(node.in zip node.out) foreach { case ((in, edgeIn), (out, edgeOut)) =>
if (alreadyRegistered) {
out.sync := in
} else {
out.sync := RegNext(in)
}
}
}
}
class IntSyncCrossingSink(sync: Int = 3)(implicit p: Parameters) extends LazyModule
{
val node = IntSyncSinkNode(sync)
lazy val module = new LazyModuleImp(this) {
(node.in zip node.out) foreach { case ((in, edgeIn), (out, edgeOut)) =>
out := SynchronizerShiftReg(in.sync, sync)
}
}
}
object IntSyncCrossingSink
{
def apply(sync: Int = 3)(implicit p: Parameters) = LazyModule(new IntSyncCrossingSink(sync)).node
}

View File

@ -0,0 +1,68 @@
// See LICENSE.SiFive for license details.
package freechips.rocketchip.interrupts
import Chisel._
import chisel3.internal.sourceinfo.SourceInfo
import freechips.rocketchip.config.Parameters
import freechips.rocketchip.diplomacy._
object IntImp extends SimpleNodeImp[IntSourcePortParameters, IntSinkPortParameters, IntEdge, Vec[Bool]]
{
def edge(pd: IntSourcePortParameters, pu: IntSinkPortParameters, p: Parameters, sourceInfo: SourceInfo) = IntEdge(pd, pu, p, sourceInfo)
def bundle(e: IntEdge) = Vec(e.source.num, Bool())
def render(e: IntEdge) = RenderedEdge(colour = "#0000ff" /* blue */, label = e.source.sources.map(_.range.size).sum.toString, flipped = true)
override def mixO(pd: IntSourcePortParameters, node: OutwardNode[IntSourcePortParameters, IntSinkPortParameters, Vec[Bool]]): IntSourcePortParameters =
pd.copy(sources = pd.sources.map { s => s.copy (nodePath = node +: s.nodePath) })
override def mixI(pu: IntSinkPortParameters, node: InwardNode[IntSourcePortParameters, IntSinkPortParameters, Vec[Bool]]): IntSinkPortParameters =
pu.copy(sinks = pu.sinks.map { s => s.copy (nodePath = node +: s.nodePath) })
}
case class IntSourceNode(portParams: Seq[IntSourcePortParameters])(implicit valName: ValName) extends SourceNode(IntImp)(portParams)
case class IntSinkNode(portParams: Seq[IntSinkPortParameters])(implicit valName: ValName) extends SinkNode(IntImp)(portParams)
case class IntAdapterNode(
sourceFn: IntSourcePortParameters => IntSourcePortParameters = { s => s },
sinkFn: IntSinkPortParameters => IntSinkPortParameters = { s => s },
num: Range.Inclusive = 0 to 999)(
implicit valName: ValName)
extends AdapterNode(IntImp)(sourceFn, sinkFn, num)
case class IntIdentityNode()(implicit valName: ValName) extends IdentityNode(IntImp)()
case class IntNexusNode(
sourceFn: Seq[IntSourcePortParameters] => IntSourcePortParameters,
sinkFn: Seq[IntSinkPortParameters] => IntSinkPortParameters,
numSourcePorts: Range.Inclusive = 0 to 128,
numSinkPorts: Range.Inclusive = 0 to 128)(
implicit valName: ValName)
extends NexusNode(IntImp)(sourceFn, sinkFn, numSourcePorts, numSinkPorts)
object IntSyncImp extends SimpleNodeImp[IntSourcePortParameters, IntSinkPortParameters, IntEdge, SyncInterrupts]
{
def edge(pd: IntSourcePortParameters, pu: IntSinkPortParameters, p: Parameters, sourceInfo: SourceInfo) = IntEdge(pd, pu, p, sourceInfo)
def bundle(e: IntEdge) = new SyncInterrupts(e)
def render(e: IntEdge) = RenderedEdge(colour = "#ff00ff" /* purple */, label = e.source.sources.map(_.range.size).sum.toString, flipped = true)
override def mixO(pd: IntSourcePortParameters, node: OutwardNode[IntSourcePortParameters, IntSinkPortParameters, SyncInterrupts]): IntSourcePortParameters =
pd.copy(sources = pd.sources.map { s => s.copy (nodePath = node +: s.nodePath) })
override def mixI(pu: IntSinkPortParameters, node: InwardNode[IntSourcePortParameters, IntSinkPortParameters, SyncInterrupts]): IntSinkPortParameters =
pu.copy(sinks = pu.sinks.map { s => s.copy (nodePath = node +: s.nodePath) })
}
case class IntSyncIdentityNode()(implicit valName: ValName) extends IdentityNode(IntSyncImp)()
case class IntSyncSourceNode(alreadyRegistered: Boolean)(implicit valName: ValName)
extends MixedAdapterNode(IntImp, IntSyncImp)(
dFn = { p => p },
uFn = { p => p })
{
override lazy val nodedebugstring = s"alreadyRegistered:${alreadyRegistered}"
}
case class IntSyncSinkNode(sync: Int)(implicit valName: ValName)
extends MixedAdapterNode(IntSyncImp, IntImp)(
dFn = { p => p },
uFn = { p => p })
{
override lazy val nodedebugstring = s"sync:${sync}"
}

View File

@ -0,0 +1,61 @@
// See LICENSE.SiFive for license details.
package freechips.rocketchip.interrupts
import Chisel._
import chisel3.internal.sourceinfo.SourceInfo
import freechips.rocketchip.config.Parameters
import freechips.rocketchip.diplomacy._
// A potentially empty half-open range; [start, end)
case class IntRange(start: Int, end: Int)
{
require (start >= 0)
require (start <= end)
def size = end - start
def overlaps(x: IntRange) = start < x.end && x.start < end
def offset(x: Int) = IntRange(x+start, x+end)
}
object IntRange
{
implicit def apply(end: Int): IntRange = apply(0, end)
}
case class IntSourceParameters(
range: IntRange,
resources: Seq[Resource] = Seq(),
nodePath: Seq[BaseNode] = Seq())
{
val name = nodePath.lastOption.map(_.lazyModule.name).getOrElse("disconnected")
}
case class IntSinkParameters(
nodePath: Seq[BaseNode] = Seq())
{
val name = nodePath.lastOption.map(_.lazyModule.name).getOrElse("disconnected")
}
case class IntSourcePortParameters(sources: Seq[IntSourceParameters])
{
val num = sources.map(_.range.size).sum
// The interrupts mapping must not overlap
sources.map(_.range).combinations(2).foreach { case Seq(a, b) => require (!a.overlaps(b)) }
// The interrupts must perfectly cover the range
require (sources.isEmpty || sources.map(_.range.end).max == num)
}
object IntSourcePortSimple
{
def apply(num: Int = 1, ports: Int = 1, sources: Int = 1, resources: Seq[Resource] = Nil) =
if (num == 0) Nil else
Seq.fill(ports)(IntSourcePortParameters(Seq.fill(sources)(IntSourceParameters(range = IntRange(0, num), resources = resources))))
}
case class IntSinkPortParameters(sinks: Seq[IntSinkParameters])
object IntSinkPortSimple
{
def apply(ports: Int = 1, sinks: Int = 1) =
Seq.fill(ports)(IntSinkPortParameters(Seq.fill(sinks)(IntSinkParameters())))
}
case class IntEdge(source: IntSourcePortParameters, sink: IntSinkPortParameters, params: Parameters, sourceInfo: SourceInfo)

View File

@ -0,0 +1,23 @@
// See LICENSE.SiFive for license details.
package freechips.rocketchip.interrupts
import Chisel._
import freechips.rocketchip.config.Parameters
import freechips.rocketchip.diplomacy._
class IntXbar()(implicit p: Parameters) extends LazyModule
{
val intnode = IntNexusNode(
sinkFn = { _ => IntSinkPortParameters(Seq(IntSinkParameters())) },
sourceFn = { seq =>
IntSourcePortParameters((seq zip seq.map(_.num).scanLeft(0)(_+_).init).map {
case (s, o) => s.sources.map(z => z.copy(range = z.range.offset(o)))
}.flatten)
})
lazy val module = new LazyModuleImp(this) {
val cat = intnode.in.map { case (i, e) => i.take(e.source.num) }.flatten
intnode.out.foreach { case (o, _) => o := cat }
}
}

View File

@ -0,0 +1,15 @@
// See LICENSE.SiFive for license details.
package freechips.rocketchip
import Chisel._
import freechips.rocketchip.diplomacy._
package object interrupts
{
type IntInwardNode = InwardNodeHandle[IntSourcePortParameters, IntSinkPortParameters, Vec[Bool]]
type IntOutwardNode = OutwardNodeHandle[IntSourcePortParameters, IntSinkPortParameters, Vec[Bool]]
type IntNode = NodeHandle[IntSourcePortParameters, IntSinkPortParameters, Vec[Bool], IntSourcePortParameters, IntSinkPortParameters, Vec[Bool]]
type IntSyncInwardNode = InwardNodeHandle[IntSourcePortParameters, IntSinkPortParameters, SyncInterrupts]
type IntSyncOutwardNode = OutwardNodeHandle[IntSourcePortParameters, IntSinkPortParameters, SyncInterrupts]
}

View File

@ -11,6 +11,7 @@ import freechips.rocketchip.tile._
import freechips.rocketchip.diplomacy._
import freechips.rocketchip.regmapper._
import freechips.rocketchip.tilelink._
import freechips.rocketchip.interrupts._
trait BusErrors extends Bundle {
def toErrorList: List[Option[Valid[UInt]]]

View File

@ -10,6 +10,7 @@ import freechips.rocketchip.coreplex.CacheBlockBytes
import freechips.rocketchip.diplomacy._
import freechips.rocketchip.tile._
import freechips.rocketchip.tilelink._
import freechips.rocketchip.interrupts._
import freechips.rocketchip.util._
class ScratchpadSlavePort(address: AddressSet, coreDataBytes: Int, usingAtomics: Boolean)(implicit p: Parameters) extends LazyModule {

View File

@ -5,7 +5,7 @@ package freechips.rocketchip.tile
import Chisel._
import freechips.rocketchip.config.Parameters
import freechips.rocketchip.tilelink.{IntSinkNode, IntSinkPortSimple}
import freechips.rocketchip.interrupts.{IntSinkNode, IntSinkPortSimple}
import freechips.rocketchip.util._
class TileInterrupts(implicit p: Parameters) extends CoreBundle()(p) {

View File

@ -9,6 +9,7 @@ import freechips.rocketchip.coreplex._
import freechips.rocketchip.diplomacy._
import freechips.rocketchip.rocket._
import freechips.rocketchip.tilelink._
import freechips.rocketchip.interrupts._
import freechips.rocketchip.util._
case class RocketTileParams(
@ -18,11 +19,12 @@ case class RocketTileParams(
rocc: Seq[RoCCParams] = Nil,
btb: Option[BTBParams] = Some(BTBParams()),
dataScratchpadBytes: Int = 0,
boundaryBuffers: Boolean = false,
trace: Boolean = false,
hcfOnUncorrectable: Boolean = false,
name: Option[String] = Some("tile"),
hartid: Int = 0) extends TileParams {
hartid: Int = 0,
boundaryBuffers: Boolean = false // if synthesized with hierarchical PnR, cut feed-throughs?
) extends TileParams {
require(icache.isDefined)
require(dcache.isDefined)
}
@ -187,38 +189,44 @@ class RocketTileWrapperBundle[+L <: RocketTileWrapper](_outer: L) extends BaseTi
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) {
val rocket = LazyModule(new RocketTile(rtp))
val asyncIntNode : IntInwardNode
val periphIntNode : IntInwardNode
val coreIntNode : IntInwardNode
val intOutputNode = rocket.intOutputNode
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
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)) {
// signals that do not change based on crossing type:
rocket.module.io.hartid := io.hartid
@ -227,76 +235,3 @@ abstract class RocketTileWrapper(rtp: RocketTileParams)(implicit p: Parameters)
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
}

View File

@ -7,6 +7,7 @@ import chisel3.internal.sourceinfo.SourceInfo
import freechips.rocketchip.config.Parameters
import freechips.rocketchip.diplomacy._
import freechips.rocketchip.util._
import freechips.rocketchip.coreplex.{CrossingWrapper, AsynchronousCrossing}
class TLAsyncCrossingSource(sync: Int = 3)(implicit p: Parameters) extends LazyModule
{
@ -85,6 +86,7 @@ object TLAsyncCrossingSink
}
}
@deprecated("TLAsyncCrossing is fragile. Use TLAsyncCrossingSource and TLAsyncCrossingSink", "rocket-chip 1.2")
class TLAsyncCrossing(depth: Int = 8, sync: Int = 3)(implicit p: Parameters) extends LazyModule
{
val source = LazyModule(new TLAsyncCrossingSource(sync))
@ -113,26 +115,19 @@ import freechips.rocketchip.unittest._
class TLRAMAsyncCrossing(txns: Int)(implicit p: Parameters) extends LazyModule {
val model = LazyModule(new TLRAMModel("AsyncCrossing"))
val ram = LazyModule(new TLRAM(AddressSet(0x0, 0x3ff)))
val fuzz = LazyModule(new TLFuzzer(txns))
val cross = LazyModule(new TLAsyncCrossing)
val island = LazyModule(new CrossingWrapper(AsynchronousCrossing(8)))
val ram = island { LazyModule(new TLRAM(AddressSet(0x0, 0x3ff))) }
model.node := fuzz.node
cross.node := TLFragmenter(4, 256)(TLDelayer(0.1)(model.node))
ram.node := cross.node
ram.node := island.crossTLIn := TLFragmenter(4, 256)(TLDelayer(0.1)(model.node))
lazy val module = new LazyModuleImp(this) with UnitTestModule {
io.finished := fuzz.module.io.finished
// Shove the RAM into another clock domain
val clocks = Module(new Pow2ClockDivider(2))
ram.module.clock := clocks.io.clock_out
// ... and safely cross TL2 into it
cross.module.io.in_clock := clock
cross.module.io.in_reset := reset
cross.module.io.out_clock := clocks.io.clock_out
cross.module.io.out_reset := reset
island.module.clock := clocks.io.clock_out
}
}

View File

@ -71,28 +71,10 @@ object TLBuffer
buffer.node :=? x
buffer.node
}
}
class TLBufferChain(depth: Int)(implicit p: Parameters) extends LazyModule {
val buf_chain = List.fill(depth)(LazyModule(new TLBuffer(BufferParams.default)))
val node = if (depth > 0) {
(buf_chain.init zip buf_chain.tail) foreach { case (prev, next) => next.node :=? prev.node }
NodeHandle(buf_chain.head.node, buf_chain.last.node)
} else {
TLIdentityNode()
}
lazy val module = new LazyModuleImp(this) { }
}
object TLBufferChain
{
def apply(depth: Int)(x: TLOutwardNode)(implicit p: Parameters, sourceInfo: SourceInfo): TLOutwardNode = {
if (depth > 0) {
val buffer = LazyModule(new TLBufferChain(depth))
buffer.node :=? x
buffer.node
} else {
x
}
def chain(depth: Int, name: Option[String] = None)(implicit p: Parameters): Seq[TLNode] = {
val buffers = Seq.fill(depth) { LazyModule(new TLBuffer()) }
name.foreach { n => buffers.zipWithIndex.foreach { case (b, i) => b.suggestName(s"${n}_${i}") } }
buffers.map(_.node)
}
}

View File

@ -68,34 +68,24 @@ abstract class TLBusWrapper(params: TLBusParams, val busName: String)(implicit p
protected def inwardNode: TLInwardNode = xbar.node
protected def inwardBufNode: TLInwardNode = master_buffer.node
protected def bufferChain(depth: Int, name: Option[String] = None): (TLInwardNode, TLOutwardNode) = {
SourceCardinality { implicit p =>
val chain = LazyModule(new TLBufferChain(depth))
name.foreach { n => chain.suggestName(s"${busName}_${n}_TLBufferChain")}
(chain.node, chain.node)
}
}
def bufferFromMasters: TLInwardNode = inwardBufNode
def bufferToSlaves: TLOutwardNode = outwardBufNode
def toSyncSlaves(name: Option[String] = None, addBuffers: Int = 0): TLOutwardNode = SinkCardinality { implicit p =>
TLBufferChain(addBuffers)(outwardBufNode)
TLBuffer.chain(addBuffers).foldRight(outwardBufNode)(_ :=? _)
}
def toAsyncSlaves(sync: Int = 3, name: Option[String] = None, addBuffers: Int = 0): TLAsyncOutwardNode = SinkCardinality { implicit p =>
val source = LazyModule(new TLAsyncCrossingSource(sync))
name.foreach{ n => source.suggestName(s"${busName}_${n}_TLAsyncCrossingSource")}
source.node :=? TLBufferChain(addBuffers)(outwardNode)
source.node
source.node :=? TLBuffer.chain(addBuffers).foldRight(outwardNode)(_ :=? _)
}
def toRationalSlaves(name: Option[String] = None, addBuffers: Int = 0): TLRationalOutwardNode = SinkCardinality { implicit p =>
val source = LazyModule(new TLRationalCrossingSource())
name.foreach{ n => source.suggestName(s"${busName}_${n}_TLRationalCrossingSource")}
source.node :=? TLBufferChain(addBuffers)(outwardNode)
source.node
source.node :=? TLBuffer.chain(addBuffers).foldRight(outwardNode)(_ :=? _)
}
def toVariableWidthSlaves: TLOutwardNode = outwardFragNode

View File

@ -233,28 +233,16 @@ class TLFuzzRAM(txns: Int)(implicit p: Parameters) extends LazyModule
val xbar = LazyModule(new TLXbar)
val xbar2= LazyModule(new TLXbar)
val fuzz = LazyModule(new TLFuzzer(txns))
val cross = LazyModule(new TLAsyncCrossing)
model.node := fuzz.node
xbar2.node := TLAtomicAutomata()(model.node)
ram2.node := TLFragmenter(16, 256)(xbar2.node)
xbar.node := TLWidthWidget(16)(TLHintHandler()(xbar2.node))
cross.node := TLFragmenter(4, 256)(TLBuffer()(xbar.node))
ram.node := cross.node
ram.node := TLFragmenter(4, 256)(TLBuffer()(xbar.node))
gpio.node := TLFragmenter(4, 32)(TLBuffer()(xbar.node))
lazy val module = new LazyModuleImp(this) with UnitTestModule {
io.finished := fuzz.module.io.finished
// Shove the RAM into another clock domain
val clocks = Module(new Pow2ClockDivider(2))
ram.module.clock := clocks.io.clock_out
// ... and safely cross TL2 into it
cross.module.io.in_clock := clock
cross.module.io.in_reset := reset
cross.module.io.out_clock := clocks.io.clock_out
cross.module.io.out_reset := reset
}
}

View File

@ -1,121 +0,0 @@
// See LICENSE.SiFive for license details.
package freechips.rocketchip.tilelink
import Chisel._
import chisel3.internal.sourceinfo.SourceInfo
import freechips.rocketchip.config.Parameters
import freechips.rocketchip.diplomacy._
import freechips.rocketchip.util.SynchronizerShiftReg
import scala.collection.mutable.ListBuffer
import scala.math.max
// A potentially empty half-open range; [start, end)
case class IntRange(start: Int, end: Int)
{
require (start >= 0)
require (start <= end)
def size = end - start
def overlaps(x: IntRange) = start < x.end && x.start < end
def offset(x: Int) = IntRange(x+start, x+end)
}
object IntRange
{
implicit def apply(end: Int): IntRange = apply(0, end)
}
case class IntSourceParameters(
range: IntRange,
resources: Seq[Resource] = Seq(),
nodePath: Seq[BaseNode] = Seq())
{
val name = nodePath.lastOption.map(_.lazyModule.name).getOrElse("disconnected")
}
case class IntSinkParameters(
nodePath: Seq[BaseNode] = Seq())
{
val name = nodePath.lastOption.map(_.lazyModule.name).getOrElse("disconnected")
}
case class IntSourcePortParameters(sources: Seq[IntSourceParameters])
{
val num = sources.map(_.range.size).sum
// The interrupts mapping must not overlap
sources.map(_.range).combinations(2).foreach { case Seq(a, b) => require (!a.overlaps(b)) }
// The interrupts must perfectly cover the range
require (sources.isEmpty || sources.map(_.range.end).max == num)
}
object IntSourcePortSimple
{
def apply(num: Int = 1, ports: Int = 1, sources: Int = 1, resources: Seq[Resource] = Nil) =
if (num == 0) Nil else
Seq.fill(ports)(IntSourcePortParameters(Seq.fill(sources)(IntSourceParameters(range = IntRange(0, num), resources = resources))))
}
case class IntSinkPortParameters(sinks: Seq[IntSinkParameters])
object IntSinkPortSimple
{
def apply(ports: Int = 1, sinks: Int = 1) =
Seq.fill(ports)(IntSinkPortParameters(Seq.fill(sinks)(IntSinkParameters())))
}
case class IntEdge(source: IntSourcePortParameters, sink: IntSinkPortParameters, params: Parameters, sourceInfo: SourceInfo)
object IntImp extends SimpleNodeImp[IntSourcePortParameters, IntSinkPortParameters, IntEdge, Vec[Bool]]
{
def edge(pd: IntSourcePortParameters, pu: IntSinkPortParameters, p: Parameters, sourceInfo: SourceInfo) = IntEdge(pd, pu, p, sourceInfo)
def bundle(e: IntEdge) = Vec(e.source.num, Bool())
def render(e: IntEdge) = RenderedEdge(colour = "#0000ff" /* blue */, label = e.source.sources.map(_.range.size).sum.toString, flipped = true)
override def mixO(pd: IntSourcePortParameters, node: OutwardNode[IntSourcePortParameters, IntSinkPortParameters, Vec[Bool]]): IntSourcePortParameters =
pd.copy(sources = pd.sources.map { s => s.copy (nodePath = node +: s.nodePath) })
override def mixI(pu: IntSinkPortParameters, node: InwardNode[IntSourcePortParameters, IntSinkPortParameters, Vec[Bool]]): IntSinkPortParameters =
pu.copy(sinks = pu.sinks.map { s => s.copy (nodePath = node +: s.nodePath) })
}
case class IntSourceNode(portParams: Seq[IntSourcePortParameters])(implicit valName: ValName) extends SourceNode(IntImp)(portParams)
case class IntSinkNode(portParams: Seq[IntSinkPortParameters])(implicit valName: ValName) extends SinkNode(IntImp)(portParams)
case class IntAdapterNode(
sourceFn: IntSourcePortParameters => IntSourcePortParameters = { s => s },
sinkFn: IntSinkPortParameters => IntSinkPortParameters = { s => s },
num: Range.Inclusive = 0 to 999)(
implicit valName: ValName)
extends AdapterNode(IntImp)(sourceFn, sinkFn, num)
case class IntIdentityNode()(implicit valName: ValName) extends IdentityNode(IntImp)()
case class IntNexusNode(
sourceFn: Seq[IntSourcePortParameters] => IntSourcePortParameters,
sinkFn: Seq[IntSinkPortParameters] => IntSinkPortParameters,
numSourcePorts: Range.Inclusive = 0 to 128,
numSinkPorts: Range.Inclusive = 0 to 128)(
implicit valName: ValName)
extends NexusNode(IntImp)(sourceFn, sinkFn, numSourcePorts, numSinkPorts)
class IntXbar()(implicit p: Parameters) extends LazyModule
{
val intnode = IntNexusNode(
sinkFn = { _ => IntSinkPortParameters(Seq(IntSinkParameters())) },
sourceFn = { seq =>
IntSourcePortParameters((seq zip seq.map(_.num).scanLeft(0)(_+_).init).map {
case (s, o) => s.sources.map(z => z.copy(range = z.range.offset(o)))
}.flatten)
})
lazy val module = new LazyModuleImp(this) {
val cat = intnode.in.map { case (i, e) => i.take(e.source.num) }.flatten
intnode.out.foreach { case (o, _) => o := cat }
}
}
class IntXing(sync: Int = 3)(implicit p: Parameters) extends LazyModule
{
val intnode = IntAdapterNode()
lazy val module = new LazyModuleImp(this) {
(intnode.in zip intnode.out) foreach { case ((in, _), (out, _)) =>
out := SynchronizerShiftReg(in, sync)
}
}
}

View File

@ -97,6 +97,7 @@ object TLRationalCrossingSink
}
}
@deprecated("TLRationalCrossing is fragile. Use TLRationalCrossingSource and TLRationalCrossingSink", "rocket-chip 1.2")
class TLRationalCrossing(direction: RationalDirection = Symmetric)(implicit p: Parameters) extends LazyModule
{
val source = LazyModule(new TLRationalCrossingSource)

View File

@ -6,6 +6,7 @@ import Chisel._
import freechips.rocketchip.config.Parameters
import freechips.rocketchip.diplomacy._
import freechips.rocketchip.regmapper._
import freechips.rocketchip.interrupts._
import freechips.rocketchip.util.HeterogeneousBag
import scala.math.{min,max}

View File

@ -9,13 +9,11 @@ package object tilelink
{
type TLInwardNode = InwardNodeHandle[TLClientPortParameters, TLManagerPortParameters, TLBundle]
type TLOutwardNode = OutwardNodeHandle[TLClientPortParameters, TLManagerPortParameters, TLBundle]
type TLNode = NodeHandle[TLClientPortParameters, TLManagerPortParameters, TLBundle, TLClientPortParameters, TLManagerPortParameters, TLBundle]
type TLAsyncInwardNode = InwardNodeHandle[TLAsyncClientPortParameters, TLAsyncManagerPortParameters, TLAsyncBundle]
type TLAsyncOutwardNode = OutwardNodeHandle[TLAsyncClientPortParameters, TLAsyncManagerPortParameters, TLAsyncBundle]
type TLRationalInwardNode = InwardNodeHandle[TLRationalClientPortParameters, TLRationalManagerPortParameters, TLRationalBundle]
type TLRationalOutwardNode = OutwardNodeHandle[TLRationalClientPortParameters, TLRationalManagerPortParameters, TLRationalBundle]
type TLMixedNode = MixedNode[TLClientPortParameters, TLManagerPortParameters, TLEdgeIn, TLBundle,
TLClientPortParameters, TLManagerPortParameters, TLEdgeOut, TLBundle]
type IntInwardNode = InwardNodeHandle[IntSourcePortParameters, IntSinkPortParameters, Vec[Bool]]
type IntOutwardNode = OutwardNodeHandle[IntSourcePortParameters, IntSinkPortParameters, Vec[Bool]]
}

View File

@ -19,118 +19,3 @@ class CrossingIO[T <: Data](gen: T) extends Bundle {
abstract class Crossing[T <: Data] extends Module {
val io: CrossingIO[T]
}
class AsyncScope extends Module { val io = new Bundle }
object AsyncScope { def apply() = Module(new AsyncScope) }
object AsyncDecoupledCrossing
{
// takes from_source from the 'from' clock domain and puts it into the 'to' clock domain
def apply[T <: Data](from_clock: Clock, from_reset: Bool, from_source: ReadyValidIO[T], to_clock: Clock, to_reset: Bool, depth: Int = 8, sync: Int = 3): DecoupledIO[T] = {
val crossing = Module(new AsyncQueue(from_source.bits, depth, sync)).io
crossing.enq_clock := from_clock
crossing.enq_reset := from_reset
crossing.enq <> from_source
crossing.deq_clock := to_clock
crossing.deq_reset := to_reset
crossing.deq
}
}
object AsyncDecoupledTo
{
// takes source from your clock domain and puts it into the 'to' clock domain
def apply[T <: Data](to_clock: Clock, to_reset: Bool, source: ReadyValidIO[T], depth: Int = 8, sync: Int = 3): DecoupledIO[T] = {
val scope = AsyncScope()
AsyncDecoupledCrossing(scope.clock, scope.reset, source, to_clock, to_reset, depth, sync)
}
}
object AsyncDecoupledFrom
{
// takes from_source from the 'from' clock domain and puts it into your clock domain
def apply[T <: Data](from_clock: Clock, from_reset: Bool, from_source: ReadyValidIO[T], depth: Int = 8, sync: Int = 3): DecoupledIO[T] = {
val scope = AsyncScope()
AsyncDecoupledCrossing(from_clock, from_reset, from_source, scope.clock, scope.reset, depth, sync)
}
}
object PostQueueIrrevocablize
{
def apply[T <: Data](deq: DecoupledIO[T]): IrrevocableIO[T] = {
val irr = Wire(new IrrevocableIO(deq.bits))
irr.bits := deq.bits
irr.valid := deq.valid
deq.ready := irr.ready
irr
}
}
object AsyncIrrevocableCrossing {
def apply[T <: Data](from_clock: Clock, from_reset: Bool, from_source: ReadyValidIO[T], to_clock: Clock, to_reset: Bool, depth: Int = 8, sync: Int = 3): IrrevocableIO[T] = {
PostQueueIrrevocablize(AsyncDecoupledCrossing(from_clock, from_reset, from_source, to_clock, to_reset, depth, sync))
}
}
object AsyncIrrevocableTo
{
// takes source from your clock domain and puts it into the 'to' clock domain
def apply[T <: Data](to_clock: Clock, to_reset: Bool, source: ReadyValidIO[T], depth: Int = 8, sync: Int = 3): IrrevocableIO[T] = {
PostQueueIrrevocablize(AsyncDecoupledTo(to_clock, to_reset, source, depth, sync))
}
}
object AsyncIrrevocableFrom
{
// takes from_source from the 'from' clock domain and puts it into your clock domain
def apply[T <: Data](from_clock: Clock, from_reset: Bool, from_source: ReadyValidIO[T], depth: Int = 8, sync: Int = 3): IrrevocableIO[T] = {
PostQueueIrrevocablize(AsyncDecoupledFrom(from_clock, from_reset, from_source, depth, sync))
}
}
/**
* This helper object synchronizes a level-sensitive signal from one
* clock domain to another.
*/
object LevelSyncCrossing {
class SynchronizerBackend(sync: Int, _clock: Clock) extends Module(Some(_clock)) {
val io = new Bundle {
val in = Bool(INPUT)
val out = Bool(OUTPUT)
}
io.out := SynchronizerShiftReg(io.in, sync)
}
class SynchronizerFrontend(_clock: Clock) extends Module(Some(_clock)) {
val io = new Bundle {
val in = Bool(INPUT)
val out = Bool(OUTPUT)
}
io.out := RegNext(io.in)
}
def apply(from_clock: Clock, to_clock: Clock, in: Bool, sync: Int = 2): Bool = {
val front = Module(new SynchronizerFrontend(from_clock))
val back = Module(new SynchronizerBackend(sync, to_clock))
front.io.in := in
back.io.in := front.io.out
back.io.out
}
}
object LevelSyncTo {
def apply(to_clock: Clock, in: Bool, sync: Int = 2): Bool = {
val scope = AsyncScope()
LevelSyncCrossing(scope.clock, to_clock, in, sync)
}
}
object LevelSyncFrom {
def apply(from_clock: Clock, in: Bool, sync: Int = 2): Bool = {
val scope = AsyncScope()
LevelSyncCrossing(from_clock, scope.clock, in, sync)
}
}