From 7453186b59a24f8778762681d53d2ee8cebc3780 Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Thu, 19 Oct 2017 18:51:00 -0700 Subject: [PATCH 01/23] diplomacy: add reflection for parent modules to nodes --- src/main/scala/diplomacy/LazyModule.scala | 5 +++++ src/main/scala/diplomacy/Nodes.scala | 4 ++++ 2 files changed, 9 insertions(+) diff --git a/src/main/scala/diplomacy/LazyModule.scala b/src/main/scala/diplomacy/LazyModule.scala index 396135be..d76d7182 100644 --- a/src/main/scala/diplomacy/LazyModule.scala +++ b/src/main/scala/diplomacy/LazyModule.scala @@ -17,6 +17,11 @@ abstract class LazyModule()(implicit val p: Parameters) 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) diff --git a/src/main/scala/diplomacy/Nodes.scala b/src/main/scala/diplomacy/Nodes.scala index 40da6ab3..7ed31673 100644 --- a/src/main/scala/diplomacy/Nodes.scala +++ b/src/main/scala/diplomacy/Nodes.scala @@ -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 }) @@ -129,6 +131,7 @@ case class NodeHandle[DI, UI, BI <: Data, DO, UO, BO <: Data] trait InwardNodeHandle[DI, UI, BI <: Data] { protected[diplomacy] val inward: InwardNode[DI, UI, BI] + def parentsIn: Seq[LazyModule] = inward.parents 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) } @@ -170,6 +173,7 @@ trait InwardNode[DI, UI, BI <: Data] extends BaseNode with InwardNodeHandle[DI, trait OutwardNodeHandle[DO, UO, BO <: Data] { protected[diplomacy] val outward: OutwardNode[DO, UO, BO] + def parentsOut: Seq[LazyModule] = outward.parents } trait OutwardNode[DO, UO, BO <: Data] extends BaseNode with OutwardNodeHandle[DO, UO, BO] From 6bc9c9fc6ca0c41606e45742dea70fbd0619c073 Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Thu, 19 Oct 2017 18:51:22 -0700 Subject: [PATCH 02/23] coreplex: add a crossing wrapper to generalize the island pattern --- src/main/scala/coreplex/CrossingWrapper.scala | 51 +++++++++++++++++++ src/main/scala/coreplex/package.scala | 11 ++++ 2 files changed, 62 insertions(+) create mode 100644 src/main/scala/coreplex/CrossingWrapper.scala create mode 100644 src/main/scala/coreplex/package.scala diff --git a/src/main/scala/coreplex/CrossingWrapper.scala b/src/main/scala/coreplex/CrossingWrapper.scala new file mode 100644 index 00000000..d6508a3f --- /dev/null +++ b/src/main/scala/coreplex/CrossingWrapper.scala @@ -0,0 +1,51 @@ +// See LICENSE.SiFive for license details. + +package freechips.rocketchip.coreplex + +import Chisel._ +import freechips.rocketchip.config._ +import freechips.rocketchip.diplomacy._ +import freechips.rocketchip.tilelink._ + +trait HasCrossingHelper extends LazyScope +{ + this: LazyModule => + val crossing: CoreplexClockCrossing + def cross(x: TLCrossableNode, name: String): TLOutwardNode = { + val out = x.node.parentsOut.exists(_ eq this) // is the crossing exiting the wrapper? + crossing match { + case SynchronousCrossing(params) => { + val buffer = this { LazyModule(new TLBuffer(params)) } + buffer.suggestName(name + "SynchronousBuffer") + buffer.node := x.node + buffer.node + } + case RationalCrossing(direction) => { + def sourceGen = LazyModule(new TLRationalCrossingSource) + def sinkGen = LazyModule(new TLRationalCrossingSink(direction)) + val source = if (out) this { sourceGen } else sourceGen + val sink = if (out) sinkGen else this { sinkGen } + source.suggestName(name + "RationalSource") + sink.suggestName(name + "RationalSink") + source.node := x.node + sink.node := source.node + sink.node + } + case AsynchronousCrossing(depth, sync) => { + def sourceGen = this { 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 } + source.suggestName(name + "AsynchronousSource") + sink.suggestName(name + "AsynchronousSink") + source.node := x.node + sink.node := source.node + sink.node + } + } + } + // def cross(x: IntCrossableNode, name: String): IntOutwardNode = { x.node } +} + +class CrossingWrapper(val crossing: CoreplexClockCrossing)(implicit p: Parameters) extends SimpleLazyModule with HasCrossingHelper + diff --git a/src/main/scala/coreplex/package.scala b/src/main/scala/coreplex/package.scala new file mode 100644 index 00000000..a93eef0c --- /dev/null +++ b/src/main/scala/coreplex/package.scala @@ -0,0 +1,11 @@ +// See LICENSE.SiFive for license details. + +package freechips.rocketchip + +import freechips.rocketchip.tilelink._ + +package object coreplex +{ + implicit class TLCrossableNode(val node: TLOutwardNode) + implicit class IntCrossableNode(val node: IntOutwardNode) +} From c6f95570df9b18e85b5c97a73a5243b829a6ba6d Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Thu, 19 Oct 2017 20:44:54 -0700 Subject: [PATCH 03/23] IntNodes: moved from tilelink to their own package --- src/main/scala/amba/ahb/RegisterRouter.scala | 2 +- src/main/scala/amba/apb/RegisterRouter.scala | 2 +- src/main/scala/amba/axi4/RegisterRouter.scala | 2 +- src/main/scala/coreplex/BaseCoreplex.scala | 1 + src/main/scala/coreplex/InterruptBus.scala | 2 +- src/main/scala/coreplex/RocketCoreplex.scala | 1 + src/main/scala/coreplex/package.scala | 3 +- src/main/scala/devices/debug/Debug.scala | 1 + src/main/scala/devices/tilelink/Clint.scala | 1 + src/main/scala/devices/tilelink/Plic.scala | 1 + src/main/scala/interrupts/Bundles.scala | 12 ++ src/main/scala/interrupts/Crossing.scala | 20 +++ src/main/scala/interrupts/Nodes.scala | 62 +++++++++ src/main/scala/interrupts/Parameters.scala | 61 +++++++++ src/main/scala/interrupts/Xbar.scala | 23 ++++ src/main/scala/interrupts/package.scala | 14 ++ src/main/scala/rocket/BusErrorUnit.scala | 1 + .../scala/rocket/ScratchpadSlavePort.scala | 1 + src/main/scala/tile/Interrupts.scala | 2 +- src/main/scala/tile/RocketTile.scala | 1 + src/main/scala/tilelink/IntNodes.scala | 121 ------------------ src/main/scala/tilelink/RegisterRouter.scala | 1 + src/main/scala/tilelink/package.scala | 3 - 23 files changed, 208 insertions(+), 130 deletions(-) create mode 100644 src/main/scala/interrupts/Bundles.scala create mode 100644 src/main/scala/interrupts/Crossing.scala create mode 100644 src/main/scala/interrupts/Nodes.scala create mode 100644 src/main/scala/interrupts/Parameters.scala create mode 100644 src/main/scala/interrupts/Xbar.scala create mode 100644 src/main/scala/interrupts/package.scala delete mode 100644 src/main/scala/tilelink/IntNodes.scala diff --git a/src/main/scala/amba/ahb/RegisterRouter.scala b/src/main/scala/amba/ahb/RegisterRouter.scala index da1960d7..59a81611 100644 --- a/src/main/scala/amba/ahb/RegisterRouter.scala +++ b/src/main/scala/amba/ahb/RegisterRouter.scala @@ -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} diff --git a/src/main/scala/amba/apb/RegisterRouter.scala b/src/main/scala/amba/apb/RegisterRouter.scala index f83c38c9..2ebb57d8 100644 --- a/src/main/scala/amba/apb/RegisterRouter.scala +++ b/src/main/scala/amba/apb/RegisterRouter.scala @@ -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} diff --git a/src/main/scala/amba/axi4/RegisterRouter.scala b/src/main/scala/amba/axi4/RegisterRouter.scala index 32d0b1de..0da5da31 100644 --- a/src/main/scala/amba/axi4/RegisterRouter.scala +++ b/src/main/scala/amba/axi4/RegisterRouter.scala @@ -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} diff --git a/src/main/scala/coreplex/BaseCoreplex.scala b/src/main/scala/coreplex/BaseCoreplex.scala index bb004313..121ef9d1 100644 --- a/src/main/scala/coreplex/BaseCoreplex.scala +++ b/src/main/scala/coreplex/BaseCoreplex.scala @@ -5,6 +5,7 @@ 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} diff --git a/src/main/scala/coreplex/InterruptBus.scala b/src/main/scala/coreplex/InterruptBus.scala index 4c04d992..3e639f79 100644 --- a/src/main/scala/coreplex/InterruptBus.scala +++ b/src/main/scala/coreplex/InterruptBus.scala @@ -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) { diff --git a/src/main/scala/coreplex/RocketCoreplex.scala b/src/main/scala/coreplex/RocketCoreplex.scala index 442b655d..650a5098 100644 --- a/src/main/scala/coreplex/RocketCoreplex.scala +++ b/src/main/scala/coreplex/RocketCoreplex.scala @@ -9,6 +9,7 @@ import freechips.rocketchip.devices.debug.{HasPeripheryDebug, HasPeripheryDebugM 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) diff --git a/src/main/scala/coreplex/package.scala b/src/main/scala/coreplex/package.scala index a93eef0c..fbd07861 100644 --- a/src/main/scala/coreplex/package.scala +++ b/src/main/scala/coreplex/package.scala @@ -2,7 +2,8 @@ package freechips.rocketchip -import freechips.rocketchip.tilelink._ +import freechips.rocketchip.tilelink.TLOutwardNode +import freechips.rocketchip.interrupts.IntOutwardNode package object coreplex { diff --git a/src/main/scala/devices/debug/Debug.scala b/src/main/scala/devices/debug/Debug.scala index 37f85ff2..f2d2a56f 100644 --- a/src/main/scala/devices/debug/Debug.scala +++ b/src/main/scala/devices/debug/Debug.scala @@ -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 diff --git a/src/main/scala/devices/tilelink/Clint.scala b/src/main/scala/devices/tilelink/Clint.scala index 0f80640b..9cc83030 100644 --- a/src/main/scala/devices/tilelink/Clint.scala +++ b/src/main/scala/devices/tilelink/Clint.scala @@ -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} diff --git a/src/main/scala/devices/tilelink/Plic.scala b/src/main/scala/devices/tilelink/Plic.scala index 73c9d681..a6ede5b7 100644 --- a/src/main/scala/devices/tilelink/Plic.scala +++ b/src/main/scala/devices/tilelink/Plic.scala @@ -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 diff --git a/src/main/scala/interrupts/Bundles.scala b/src/main/scala/interrupts/Bundles.scala new file mode 100644 index 00000000..86691f9e --- /dev/null +++ b/src/main/scala/interrupts/Bundles.scala @@ -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()) +} diff --git a/src/main/scala/interrupts/Crossing.scala b/src/main/scala/interrupts/Crossing.scala new file mode 100644 index 00000000..67ba2075 --- /dev/null +++ b/src/main/scala/interrupts/Crossing.scala @@ -0,0 +1,20 @@ +// 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) + } + } +} diff --git a/src/main/scala/interrupts/Nodes.scala b/src/main/scala/interrupts/Nodes.scala new file mode 100644 index 00000000..5f5f86b8 --- /dev/null +++ b/src/main/scala/interrupts/Nodes.scala @@ -0,0 +1,62 @@ +// 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()(implicit valName: ValName) + extends MixedAdapterNode(IntImp, IntSyncImp)( + dFn = { p => p }, + uFn = { p => p }) + +case class IntSyncSinkNode()(implicit valName: ValName) + extends MixedAdapterNode(IntSyncImp, IntImp)( + dFn = { p => p }, + uFn = { p => p }) diff --git a/src/main/scala/interrupts/Parameters.scala b/src/main/scala/interrupts/Parameters.scala new file mode 100644 index 00000000..bb3e37a1 --- /dev/null +++ b/src/main/scala/interrupts/Parameters.scala @@ -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) diff --git a/src/main/scala/interrupts/Xbar.scala b/src/main/scala/interrupts/Xbar.scala new file mode 100644 index 00000000..556974ef --- /dev/null +++ b/src/main/scala/interrupts/Xbar.scala @@ -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 } + } +} diff --git a/src/main/scala/interrupts/package.scala b/src/main/scala/interrupts/package.scala new file mode 100644 index 00000000..9b2bef75 --- /dev/null +++ b/src/main/scala/interrupts/package.scala @@ -0,0 +1,14 @@ +// 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 IntSyncInwardNode = InwardNodeHandle[IntSourcePortParameters, IntSinkPortParameters, SyncInterrupts] + type IntSyncOutwardNode = OutwardNodeHandle[IntSourcePortParameters, IntSinkPortParameters, SyncInterrupts] +} diff --git a/src/main/scala/rocket/BusErrorUnit.scala b/src/main/scala/rocket/BusErrorUnit.scala index 7ba2bc2d..d3928fee 100644 --- a/src/main/scala/rocket/BusErrorUnit.scala +++ b/src/main/scala/rocket/BusErrorUnit.scala @@ -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]]] diff --git a/src/main/scala/rocket/ScratchpadSlavePort.scala b/src/main/scala/rocket/ScratchpadSlavePort.scala index dd8d002b..b154dfbc 100644 --- a/src/main/scala/rocket/ScratchpadSlavePort.scala +++ b/src/main/scala/rocket/ScratchpadSlavePort.scala @@ -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 { diff --git a/src/main/scala/tile/Interrupts.scala b/src/main/scala/tile/Interrupts.scala index dcccada3..0043089d 100644 --- a/src/main/scala/tile/Interrupts.scala +++ b/src/main/scala/tile/Interrupts.scala @@ -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) { diff --git a/src/main/scala/tile/RocketTile.scala b/src/main/scala/tile/RocketTile.scala index 98849fef..3fe5fe51 100644 --- a/src/main/scala/tile/RocketTile.scala +++ b/src/main/scala/tile/RocketTile.scala @@ -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( diff --git a/src/main/scala/tilelink/IntNodes.scala b/src/main/scala/tilelink/IntNodes.scala deleted file mode 100644 index 2cc6aa61..00000000 --- a/src/main/scala/tilelink/IntNodes.scala +++ /dev/null @@ -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) - } - } -} diff --git a/src/main/scala/tilelink/RegisterRouter.scala b/src/main/scala/tilelink/RegisterRouter.scala index dc49e797..44df9669 100644 --- a/src/main/scala/tilelink/RegisterRouter.scala +++ b/src/main/scala/tilelink/RegisterRouter.scala @@ -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} diff --git a/src/main/scala/tilelink/package.scala b/src/main/scala/tilelink/package.scala index e0a165b7..96e8edfa 100644 --- a/src/main/scala/tilelink/package.scala +++ b/src/main/scala/tilelink/package.scala @@ -15,7 +15,4 @@ package object tilelink 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]] } From 217575805060f09330b6588df136918a081b2a71 Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Thu, 19 Oct 2017 22:19:19 -0700 Subject: [PATCH 04/23] interrupts: implement in crossing wrapper --- src/main/scala/coreplex/CrossingWrapper.scala | 45 +++++++++++++++++-- src/main/scala/interrupts/Crossing.scala | 38 ++++++++++++++++ 2 files changed, 80 insertions(+), 3 deletions(-) diff --git a/src/main/scala/coreplex/CrossingWrapper.scala b/src/main/scala/coreplex/CrossingWrapper.scala index d6508a3f..3d483327 100644 --- a/src/main/scala/coreplex/CrossingWrapper.scala +++ b/src/main/scala/coreplex/CrossingWrapper.scala @@ -6,11 +6,13 @@ import Chisel._ import freechips.rocketchip.config._ import freechips.rocketchip.diplomacy._ import freechips.rocketchip.tilelink._ +import freechips.rocketchip.interrupts._ trait HasCrossingHelper extends LazyScope { this: LazyModule => val crossing: CoreplexClockCrossing + def cross(x: TLCrossableNode, name: String): TLOutwardNode = { val out = x.node.parentsOut.exists(_ eq this) // is the crossing exiting the wrapper? crossing match { @@ -32,7 +34,7 @@ trait HasCrossingHelper extends LazyScope sink.node } case AsynchronousCrossing(depth, sync) => { - def sourceGen = this { LazyModule(new TLAsyncCrossingSource(sync)) } + 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 } @@ -44,8 +46,45 @@ trait HasCrossingHelper extends LazyScope } } } - // def cross(x: IntCrossableNode, name: String): IntOutwardNode = { x.node } + + def cross(x: IntCrossableNode, name: String, alreadyRegistered: Boolean = false): IntOutwardNode = { + val out = x.node.parentsOut.exists(_ eq this) // is the crossing exiting the wrapper? + crossing match { + case SynchronousCrossing(_) => { + 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 } + source.suggestName(name + "SyncSource") + sink.suggestName(name + "SyncSink") + source.node := x.node + sink.node := source.node + sink.node + } + case RationalCrossing(_) => { + 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 } + source.suggestName(name + "SyncSource") + sink.suggestName(name + "SyncSink") + source.node := x.node + sink.node := source.node + sink.node + } + case AsynchronousCrossing(_, sync) => { + 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 } + source.suggestName(name + "SyncSource") + sink.suggestName(name + "SyncSink") + source.node := x.node + sink.node := source.node + sink.node + } + } + } } class CrossingWrapper(val crossing: CoreplexClockCrossing)(implicit p: Parameters) extends SimpleLazyModule with HasCrossingHelper - diff --git a/src/main/scala/interrupts/Crossing.scala b/src/main/scala/interrupts/Crossing.scala index 67ba2075..5c3f8568 100644 --- a/src/main/scala/interrupts/Crossing.scala +++ b/src/main/scala/interrupts/Crossing.scala @@ -18,3 +18,41 @@ class IntXing(sync: Int = 3)(implicit p: Parameters) extends LazyModule } } } + +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() + + 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() + + 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 +} From 95a2e6ef27a242766ead6f807db33cf898a3b448 Mon Sep 17 00:00:00 2001 From: Henry Cook Date: Thu, 19 Oct 2017 19:48:20 -0700 Subject: [PATCH 05/23] coreplex: improve tile attachment adapters --- src/main/scala/coreplex/PeripheryBus.scala | 18 ++--- src/main/scala/coreplex/RocketCoreplex.scala | 75 ++++++++++---------- src/main/scala/coreplex/SystemBus.scala | 18 ++--- src/main/scala/groundtest/Coreplex.scala | 2 +- src/main/scala/tilelink/Buffer.scala | 17 +++-- src/main/scala/tilelink/package.scala | 1 + 6 files changed, 60 insertions(+), 71 deletions(-) diff --git a/src/main/scala/coreplex/PeripheryBus.scala b/src/main/scala/coreplex/PeripheryBus.scala index d7ac4a0e..688c1910 100644 --- a/src/main/scala/coreplex/PeripheryBus.scala +++ b/src/main/scala/coreplex/PeripheryBus.scala @@ -31,27 +31,19 @@ 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 toSyncSlaves(adapt: TLOutwardNode => TLOutwardNode, name: Option[String]): TLOutwardNode = adapt(outwardBufNode) - def toAsyncSlaves(sync: Int, adapt: () => TLNodeChain, name: Option[String]): TLAsyncOutwardNode = SinkCardinality { implicit p => - val adapters = adapt() + 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")} - adapters.in :=? outwardNode - source.node :=? adapters.out + source.node :*= adapt(outwardNode) source.node } - def toRationalSlaves(adapt: () => TLNodeChain, name: Option[String]): TLRationalOutwardNode = SinkCardinality { implicit p => - val adapters = adapt() + 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")} - adapters.in :=? outwardNode - source.node :=? adapters.out + source.node :*= adapt(outwardNode) source.node } diff --git a/src/main/scala/coreplex/RocketCoreplex.scala b/src/main/scala/coreplex/RocketCoreplex.scala index 650a5098..5013cb15 100644 --- a/src/main/scala/coreplex/RocketCoreplex.scala +++ b/src/main/scala/coreplex/RocketCoreplex.scala @@ -3,6 +3,7 @@ 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} @@ -12,59 +13,57 @@ 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) + val node: Option[TLNode] = SourceCardinality { implicit p => + 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.getOrElse(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))) + def adapt(coreplex: HasPeripheryBus) + (masterNode: TLOutwardNode) + (implicit p: Parameters, sourceInfo: SourceInfo): TLOutwardNode = { + val tile_slave_blocker = + blockerCtrlAddr + .map(BasicBusBlockerParams(_, coreplex.pbus.beatBytes, coreplex.sbus.beatBytes)) + .map(bp => LazyModule(new BasicBusBlocker(bp))) val tile_slave_buffer = LazyModule(new TLBufferChain(addBuffers)) 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) + val node: Option[TLNode] = SinkCardinality { implicit p => + TLNodeChain(List( + Some(tile_slave_buffer.node), + tile_slave_blocker.map(_.node)).flatten) + } + node.foreach { _ :*= masterNode } + node.getOrElse(masterNode) } } @@ -111,20 +110,20 @@ trait HasRocketTiles extends HasTiles 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) } + sbus.fromSyncTiles(params, crossing.master.adapt(this) _, tp.name) :=* wrapper.masterNode + FlipRendering { implicit p => wrapper.slaveNode:*= pbus.toSyncSlaves(crossing.slave.adapt(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) } + 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.adapterChain(this), tp.name) :=* wrapper.masterNode - FlipRendering { implicit p => wrapper.slaveNode :*= pbus.toRationalSlaves(crossing.slave.adapterChain(this), tp.name) } + 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 } } diff --git a/src/main/scala/coreplex/SystemBus.scala b/src/main/scala/coreplex/SystemBus.scala index c07138f9..5f20477c 100644 --- a/src/main/scala/coreplex/SystemBus.scala +++ b/src/main/scala/coreplex/SystemBus.scala @@ -52,33 +52,27 @@ 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 + def fromSyncTiles(params: BufferParams, adapt: TLOutwardNode => TLOutwardNode, name: Option[String] = None): TLInwardNode = { 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 + master_splitter.node :=* adapt(tile_sink.node) tile_sink.node } - def fromRationalTiles(dir: RationalDirection, adapt: () => TLNodeChain, name: Option[String] = None): TLRationalInwardNode = { - val adapters = adapt() // wanted to be called inside SystemBus scope + def fromRationalTiles(dir: RationalDirection, adapt: TLOutwardNode => TLOutwardNode, name: Option[String] = None): TLRationalInwardNode = { 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 + master_splitter.node :=* adapt(tile_sink.node) 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 + def fromAsyncTiles(depth: Int, sync: Int, adapt: TLOutwardNode => TLOutwardNode, name: Option[String] = None): TLAsyncInwardNode = { 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 + master_splitter.node :=* adapt(tile_sink.node) tile_sink.node } diff --git a/src/main/scala/groundtest/Coreplex.scala b/src/main/scala/groundtest/Coreplex.scala index ee8ebe6b..46f86a69 100644 --- a/src/main/scala/groundtest/Coreplex.scala +++ b/src/main/scala/groundtest/Coreplex.scala @@ -26,7 +26,7 @@ class GroundTestCoreplex(implicit p: Parameters) extends BaseCoreplex )} tiles.flatMap(_.dcacheOpt).foreach { - sbus.fromSyncTiles(BufferParams.default, TileMasterPortParams().adapterChain(this)) :=* _.node + sbus.fromSyncTiles(BufferParams.default, TileMasterPortParams().adapt(this) _) :=* _.node } val pbusRAM = LazyModule(new TLRAM(AddressSet(testRamAddr, 0xffff), true, false, pbus.beatBytes)) diff --git a/src/main/scala/tilelink/Buffer.scala b/src/main/scala/tilelink/Buffer.scala index bd35a614..dcf54d81 100644 --- a/src/main/scala/tilelink/Buffer.scala +++ b/src/main/scala/tilelink/Buffer.scala @@ -73,15 +73,18 @@ object TLBuffer } } -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) +object TLNodeChain { + def apply(nodes: Seq[TLNode])(implicit p: Parameters): Option[TLNode] = if(nodes.size > 0) { + (nodes.init zip nodes.tail) foreach { case (prev, next) => next :=? prev } + Some(NodeHandle(nodes.head, nodes.last)) } else { - TLIdentityNode() + None } - lazy val module = new LazyModuleImp(this) { } +} + +class TLBufferChain(depth: Int)(implicit p: Parameters) extends SimpleLazyModule { + val buf_chain = List.fill(depth)(LazyModule(new TLBuffer(BufferParams.default))) + val node = TLNodeChain(buf_chain.map(_.node)).getOrElse(TLIdentityNode()) } object TLBufferChain diff --git a/src/main/scala/tilelink/package.scala b/src/main/scala/tilelink/package.scala index 96e8edfa..140212d2 100644 --- a/src/main/scala/tilelink/package.scala +++ b/src/main/scala/tilelink/package.scala @@ -9,6 +9,7 @@ package object tilelink { type TLInwardNode = InwardNodeHandle[TLClientPortParameters, TLManagerPortParameters, TLBundle] type TLOutwardNode = OutwardNodeHandle[TLClientPortParameters, TLManagerPortParameters, TLBundle] + type TLNode = TLInwardNode with TLOutwardNode type TLAsyncInwardNode = InwardNodeHandle[TLAsyncClientPortParameters, TLAsyncManagerPortParameters, TLAsyncBundle] type TLAsyncOutwardNode = OutwardNodeHandle[TLAsyncClientPortParameters, TLAsyncManagerPortParameters, TLAsyncBundle] type TLRationalInwardNode = InwardNodeHandle[TLRationalClientPortParameters, TLRationalManagerPortParameters, TLRationalBundle] From 9fe35382ea1bc56f81d60c28692bc1f3ff462f93 Mon Sep 17 00:00:00 2001 From: Henry Cook Date: Thu, 19 Oct 2017 20:20:21 -0700 Subject: [PATCH 06/23] sbus: tile adapters in sbus scope --- src/main/scala/coreplex/SystemBus.scala | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/scala/coreplex/SystemBus.scala b/src/main/scala/coreplex/SystemBus.scala index 5f20477c..008b31ab 100644 --- a/src/main/scala/coreplex/SystemBus.scala +++ b/src/main/scala/coreplex/SystemBus.scala @@ -52,7 +52,7 @@ class SystemBus(params: SystemBusParams)(implicit p: Parameters) extends TLBusWr def fromFrontBus: TLInwardNode = master_splitter.node - def fromSyncTiles(params: BufferParams, adapt: TLOutwardNode => TLOutwardNode, name: Option[String] = None): TLInwardNode = { + def fromSyncTiles(params: BufferParams, adapt: TLOutwardNode => TLOutwardNode, name: Option[String] = None): TLInwardNode = this { val tile_sink = LazyModule(new TLBuffer(params)) name.foreach { n => tile_sink.suggestName(s"${busName}_${n}_TLBuffer") } @@ -60,7 +60,7 @@ class SystemBus(params: SystemBusParams)(implicit p: Parameters) extends TLBusWr tile_sink.node } - def fromRationalTiles(dir: RationalDirection, adapt: TLOutwardNode => TLOutwardNode, name: Option[String] = None): TLRationalInwardNode = { + 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") } @@ -68,7 +68,7 @@ class SystemBus(params: SystemBusParams)(implicit p: Parameters) extends TLBusWr tile_sink.node } - def fromAsyncTiles(depth: Int, sync: Int, adapt: TLOutwardNode => TLOutwardNode, name: Option[String] = None): TLAsyncInwardNode = { + 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") } From b48ab985d0433d6da436a64ec03d65778485fa31 Mon Sep 17 00:00:00 2001 From: Henry Cook Date: Mon, 23 Oct 2017 09:39:01 -0700 Subject: [PATCH 07/23] coreplex: RocketTileWrapper now HasCrossingHelper --- src/main/scala/coreplex/BaseCoreplex.scala | 6 - src/main/scala/coreplex/CrossingWrapper.scala | 60 ++++---- src/main/scala/coreplex/PeripheryBus.scala | 31 ++-- src/main/scala/coreplex/RocketCoreplex.scala | 138 +++++++++--------- src/main/scala/coreplex/SystemBus.scala | 33 ++--- src/main/scala/diplomacy/LazyModule.scala | 7 +- src/main/scala/groundtest/Coreplex.scala | 6 +- src/main/scala/tile/RocketTile.scala | 123 +++------------- 8 files changed, 161 insertions(+), 243 deletions(-) diff --git a/src/main/scala/coreplex/BaseCoreplex.scala b/src/main/scala/coreplex/BaseCoreplex.scala index 121ef9d1..b00b0681 100644 --- a/src/main/scala/coreplex/BaseCoreplex.scala +++ b/src/main/scala/coreplex/BaseCoreplex.scala @@ -12,12 +12,6 @@ import freechips.rocketchip.tile.{BaseTile, TileParams, SharedMemoryTLEdge, HasE 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) diff --git a/src/main/scala/coreplex/CrossingWrapper.scala b/src/main/scala/coreplex/CrossingWrapper.scala index 3d483327..6a7b3a93 100644 --- a/src/main/scala/coreplex/CrossingWrapper.scala +++ b/src/main/scala/coreplex/CrossingWrapper.scala @@ -7,30 +7,34 @@ import freechips.rocketchip.config._ import freechips.rocketchip.diplomacy._ import freechips.rocketchip.tilelink._ 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 { this: LazyModule => 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? crossing match { case SynchronousCrossing(params) => { - val buffer = this { LazyModule(new TLBuffer(params)) } - buffer.suggestName(name + "SynchronousBuffer") - buffer.node := x.node - buffer.node + // !!! Why does star resolution fail for tile with no slave devices? + // this { TLBuffer(params)(x.node) } + x.node } case RationalCrossing(direction) => { def sourceGen = LazyModule(new TLRationalCrossingSource) def sinkGen = LazyModule(new TLRationalCrossingSink(direction)) val source = if (out) this { sourceGen } else sourceGen val sink = if (out) sinkGen else this { sinkGen } - source.suggestName(name + "RationalSource") - sink.suggestName(name + "RationalSink") - source.node := x.node - sink.node := source.node + source.node :=? x.node + sink.node :=? source.node sink.node } case AsynchronousCrossing(depth, sync) => { @@ -38,27 +42,29 @@ trait HasCrossingHelper extends LazyScope def sinkGen = LazyModule(new TLAsyncCrossingSink(depth, sync)) val source = if (out) this { sourceGen } else sourceGen val sink = if (out) sinkGen else this { sinkGen } - source.suggestName(name + "AsynchronousSource") - sink.suggestName(name + "AsynchronousSink") - source.node := x.node - sink.node := source.node + source.node :=? x.node + sink.node :=? source.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? - crossing match { + overrideCrossing.getOrElse(crossing) match { case SynchronousCrossing(_) => { 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 } - source.suggestName(name + "SyncSource") - sink.suggestName(name + "SyncSink") - source.node := x.node - sink.node := source.node + name.map(_ + "SyncSource").foreach(source.suggestName) + name.map(_ + "SyncSink").foreach(sink.suggestName) + source.node :=? x.node + sink.node :=? source.node sink.node } case RationalCrossing(_) => { @@ -66,10 +72,10 @@ trait HasCrossingHelper extends LazyScope def sinkGen = LazyModule(new IntSyncCrossingSink(1)) val source = if (out) this { sourceGen } else sourceGen val sink = if (out) sinkGen else this { sinkGen } - source.suggestName(name + "SyncSource") - sink.suggestName(name + "SyncSink") - source.node := x.node - sink.node := source.node + name.map(_ + "SyncSource").foreach(source.suggestName) + name.map(_ + "SyncSink").foreach(sink.suggestName) + source.node :=? x.node + sink.node :=? source.node sink.node } case AsynchronousCrossing(_, sync) => { @@ -77,10 +83,10 @@ trait HasCrossingHelper extends LazyScope def sinkGen = LazyModule(new IntSyncCrossingSink(sync)) val source = if (out) this { sourceGen } else sourceGen val sink = if (out) sinkGen else this { sinkGen } - source.suggestName(name + "SyncSource") - sink.suggestName(name + "SyncSink") - source.node := x.node - sink.node := source.node + name.map(_ + "SyncSource").foreach(source.suggestName) + name.map(_ + "SyncSink").foreach(sink.suggestName) + source.node :=? x.node + sink.node :=? source.node sink.node } } diff --git a/src/main/scala/coreplex/PeripheryBus.scala b/src/main/scala/coreplex/PeripheryBus.scala index 688c1910..c3a6939d 100644 --- a/src/main/scala/coreplex/PeripheryBus.scala +++ b/src/main/scala/coreplex/PeripheryBus.scala @@ -31,27 +31,26 @@ class PeripheryBus(params: PeripheryBusParams)(implicit p: Parameters) extends T 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 atomics = LazyModule(new TLAtomicAutomata(arithmetic = params.arithmetic)) inwardBufNode := 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, diff --git a/src/main/scala/coreplex/RocketCoreplex.scala b/src/main/scala/coreplex/RocketCoreplex.scala index 5013cb15..d3f5859d 100644 --- a/src/main/scala/coreplex/RocketCoreplex.scala +++ b/src/main/scala/coreplex/RocketCoreplex.scala @@ -18,6 +18,7 @@ case class TileMasterPortParams( addBuffers: Int = 0, blockerCtrlAddr: Option[BigInt] = None, cork: Option[Boolean] = None) { + def adapt(coreplex: HasPeripheryBus) (masterNode: 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_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 => - TLNodeChain(List( - Some(tile_master_buffer.node), - Some(tile_master_fixer.node), - tile_master_blocker.map(_.node), - tile_master_cork.map(_.node)).flatten) - } + tile_master_blocker.foreach { _.controlNode := coreplex.pbus.toVariableWidthSlaves } node.foreach { _ :=* masterNode } + node.getOrElse(masterNode) } } @@ -46,6 +46,7 @@ case class TileMasterPortParams( case class TileSlavePortParams( addBuffers: Int = 0, blockerCtrlAddr: Option[BigInt] = None) { + def adapt(coreplex: HasPeripheryBus) (masterNode: TLOutwardNode) (implicit p: Parameters, sourceInfo: SourceInfo): TLOutwardNode = { @@ -55,14 +56,13 @@ case class TileSlavePortParams( .map(bp => LazyModule(new BasicBusBlocker(bp))) 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 => - TLNodeChain(List( - Some(tile_slave_buffer.node), - tile_slave_blocker.map(_.node)).flatten) - } + tile_slave_blocker.foreach { _.controlNode := coreplex.pbus.toVariableWidthSlaves } node.foreach { _ :*= masterNode } + node.getOrElse(masterNode) } } @@ -70,7 +70,8 @@ case class TileSlavePortParams( case class RocketCrossingParams( crossingType: CoreplexClockCrossing = SynchronousCrossing(), master: TileMasterPortParams = TileMasterPortParams(), - slave: TileSlavePortParams = TileSlavePortParams()) { + slave: TileSlavePortParams = TileSlavePortParams(), + boundaryBuffers: Boolean = false) { def knownRatio: Option[Int] = crossingType match { case RationalCrossing(_) => Some(2) case _ => None @@ -95,67 +96,72 @@ 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, + 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 { - case SynchronousCrossing(params) => { - val wrapper = LazyModule(new SyncRocketTile(tp)(pWithExtra)) - sbus.fromSyncTiles(params, crossing.master.adapt(this) _, tp.name) :=* wrapper.masterNode - FlipRendering { implicit p => wrapper.slaveNode:*= pbus.toSyncSlaves(crossing.slave.adapt(this) _, tp.name) } - wrapper - } - 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 + // Connect the master ports of the tile to the system bus + sbus.fromTile( + adapt = {x: TLOutwardNode => wrapper.cross(x) } andThen + crossing.master.adapt(this) _, + from = wrapper.masterNode, + name = tp.name) - // 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( + adapt = {x: TLOutwardNode => wrapper.cross(x) } compose + crossing.slave.adapt(this) _, + to = wrapper.slaveNode, + name = tp.name) - val periphIntXbar = LazyModule(new IntXbar) - periphIntXbar.suggestName("periphIntXbar") - periphIntXbar.intnode := clint.intnode // msip+mtip - periphIntXbar.intnode := plic.intnode // meip + // 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 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 - 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) - coreIntXbar.suggestName("coreIntXbar") - lip.foreach { coreIntXbar.intnode := _ } // lip - wrapper.coreIntNode := coreIntXbar.intnode + val coreIntXbar = LazyModule(new IntXbar).suggestName(tp.name.map(_ + "CoreIntXbar")) + lip.foreach { coreIntXbar.intnode := _ } // lip + wrapper.intXbar.intnode := coreIntXbar.intnode // 3. never crosses - wrapper.intOutputNode.foreach { case int => - val rocketIntXing = LazyModule(new IntXing(wrapper.outputInterruptXingLatency)) - FlipRendering { implicit p => rocketIntXing.intnode := int } - plic.intnode := rocketIntXing.intnode + wrapper.rocket.intOutputNode.foreach { i => // 4. conditionally crosses + plic.intnode := FlipRendering { implicit p => + wrapper.cross(name = tp.name.map(_ + "PeriphIntOutput"))(x = i) + } } wrapper diff --git a/src/main/scala/coreplex/SystemBus.scala b/src/main/scala/coreplex/SystemBus.scala index 008b31ab..a87726a6 100644 --- a/src/main/scala/coreplex/SystemBus.scala +++ b/src/main/scala/coreplex/SystemBus.scala @@ -52,28 +52,17 @@ class SystemBus(params: SystemBusParams)(implicit p: Parameters) extends TLBusWr def fromFrontBus: TLInwardNode = master_splitter.node - def fromSyncTiles(params: BufferParams, adapt: TLOutwardNode => TLOutwardNode, name: Option[String] = None): TLInwardNode = this { - val tile_sink = LazyModule(new TLBuffer(params)) - name.foreach { n => tile_sink.suggestName(s"${busName}_${n}_TLBuffer") } - - master_splitter.node :=* adapt(tile_sink.node) - tile_sink.node - } - - 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 fromTile( + adapt: TLOutwardNode => TLOutwardNode, + from: TLOutwardNode, + name: Option[String] = None) { + this { + LazyScope(s"${busName}FromTile${name.getOrElse("")}") { + SourceCardinality { implicit p => + master_splitter.node :=* adapt(from) + } + } + } } def fromSyncPorts(params: BufferParams = BufferParams.default, name: Option[String] = None): TLInwardNode = { diff --git a/src/main/scala/diplomacy/LazyModule.scala b/src/main/scala/diplomacy/LazyModule.scala index d76d7182..e994f70f 100644 --- a/src/main/scala/diplomacy/LazyModule.scala +++ b/src/main/scala/diplomacy/LazyModule.scala @@ -25,8 +25,13 @@ abstract class LazyModule()(implicit val p: Parameters) 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 => diff --git a/src/main/scala/groundtest/Coreplex.scala b/src/main/scala/groundtest/Coreplex.scala index 46f86a69..d8eff447 100644 --- a/src/main/scala/groundtest/Coreplex.scala +++ b/src/main/scala/groundtest/Coreplex.scala @@ -25,8 +25,10 @@ class GroundTestCoreplex(implicit p: Parameters) extends BaseCoreplex }) )} - tiles.flatMap(_.dcacheOpt).foreach { - sbus.fromSyncTiles(BufferParams.default, TileMasterPortParams().adapt(this) _) :=* _.node + tiles.flatMap(_.dcacheOpt).foreach { dc => + sbus.fromTile( + adapt = TileMasterPortParams(addBuffers = 1).adapt(this) _, + from = dc.node) } val pbusRAM = LazyModule(new TLRAM(AddressSet(testRamAddr, 0xffff), true, false, pbus.beatBytes)) diff --git a/src/main/scala/tile/RocketTile.scala b/src/main/scala/tile/RocketTile.scala index 3fe5fe51..7791c2d9 100644 --- a/src/main/scala/tile/RocketTile.scala +++ b/src/main/scala/tile/RocketTile.scala @@ -19,7 +19,6 @@ 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"), @@ -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) } -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, + val boundaryBuffers: Boolean = false) + (implicit p: Parameters) extends BaseTile(params) with HasCrossingHelper { + + 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) - 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 @@ -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 } } } - -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 -} From e894d64bca5696fddb50f3d33d86847a4818cc1d Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Tue, 24 Oct 2017 23:34:16 -0700 Subject: [PATCH 08/23] diplomacy: support := composition This makes it possible to treat chained composition associatively. x := y :=? z :=* a ... It also makes it easy to chain multiple optional adapters: node :=? (Seq(a, b) ++ c ++ d) --- src/main/scala/diplomacy/Nodes.scala | 72 +++++++++++++++++++-------- src/main/scala/tilelink/Buffer.scala | 6 +++ src/main/scala/tilelink/package.scala | 2 +- 3 files changed, 57 insertions(+), 23 deletions(-) diff --git a/src/main/scala/diplomacy/Nodes.scala b/src/main/scala/diplomacy/Nodes.scala index 7ed31673..868fffee 100644 --- a/src/main/scala/diplomacy/Nodes.scala +++ b/src/main/scala/diplomacy/Nodes.scala @@ -119,23 +119,51 @@ 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] = { inward.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] = { inward.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] = { inward.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] = { inward.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] = { inward.bind(h, BIND_ONCE); this } + override def :*= (h: OutwardNodeHandle[DI, UI, BI])(implicit p: Parameters, sourceInfo: SourceInfo): OutwardNodeHandle[DO, UO, BO] = { inward.bind(h, BIND_STAR); this } + override def :=* (h: OutwardNodeHandle[DI, UI, BI])(implicit p: Parameters, sourceInfo: SourceInfo): OutwardNodeHandle[DO, UO, BO] = { inward.bind(h, BIND_QUERY); this } + override def :=? (h: OutwardNodeHandle[DI, UI, BI])(implicit p: Parameters, sourceInfo: SourceInfo): OutwardNodeHandle[DO, UO, BO] = { inward.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 parentsIn: Seq[LazyModule] = inward.parents - 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) } + // 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] = { inward.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] = { inward.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] = { inward.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] = { inward.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 = { inward.bind(h, BIND_ONCE); NoHandleObject } + def :*= (h: OutwardNodeHandle[DI, UI, BI])(implicit p: Parameters, sourceInfo: SourceInfo): NoHandle = { inward.bind(h, BIND_STAR); NoHandleObject } + def :=* (h: OutwardNodeHandle[DI, UI, BI])(implicit p: Parameters, sourceInfo: SourceInfo): NoHandle = { inward.bind(h, BIND_QUERY); NoHandleObject } + def :=? (h: OutwardNodeHandle[DI, UI, BI])(implicit p: Parameters, sourceInfo: SourceInfo): NoHandle = { inward.bind(h, p(CardinalityInferenceDirectionKey)); NoHandleObject } } sealed trait NodeBinding @@ -143,6 +171,15 @@ 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 @@ -168,9 +205,11 @@ 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: OutwardNodeHandle[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 parentsOut: Seq[LazyModule] = outward.parents @@ -215,7 +254,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] @@ -341,7 +380,7 @@ 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: OutwardNodeHandle[DI, UI, BI], binding: NodeBinding)(implicit p: Parameters, sourceInfo: SourceInfo) { val x = this // x := y val y = h.outward val info = sourceLine(sourceInfo, " at ", "") @@ -354,17 +393,6 @@ 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) => val re = inner.render(e) diff --git a/src/main/scala/tilelink/Buffer.scala b/src/main/scala/tilelink/Buffer.scala index dcf54d81..ba7006e2 100644 --- a/src/main/scala/tilelink/Buffer.scala +++ b/src/main/scala/tilelink/Buffer.scala @@ -71,6 +71,12 @@ object TLBuffer buffer.node :=? x buffer.node } + + 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) + } } object TLNodeChain { diff --git a/src/main/scala/tilelink/package.scala b/src/main/scala/tilelink/package.scala index 140212d2..4dc8cc24 100644 --- a/src/main/scala/tilelink/package.scala +++ b/src/main/scala/tilelink/package.scala @@ -9,7 +9,7 @@ package object tilelink { type TLInwardNode = InwardNodeHandle[TLClientPortParameters, TLManagerPortParameters, TLBundle] type TLOutwardNode = OutwardNodeHandle[TLClientPortParameters, TLManagerPortParameters, TLBundle] - type TLNode = TLInwardNode with TLOutwardNode + 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] From 8c5e8dd0712f891e77148c7267f6205cbb3eca83 Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Wed, 25 Oct 2017 02:27:01 -0700 Subject: [PATCH 09/23] coreplex: leverage improved := composition --- src/main/scala/coreplex/CrossingWrapper.scala | 4 +- src/main/scala/coreplex/PeripheryBus.scala | 7 +--- src/main/scala/coreplex/RocketCoreplex.scala | 39 +++++-------------- src/main/scala/coreplex/SystemBus.scala | 7 +--- src/main/scala/groundtest/Coreplex.scala | 4 +- src/main/scala/tilelink/Buffer.scala | 11 +----- 6 files changed, 16 insertions(+), 56 deletions(-) diff --git a/src/main/scala/coreplex/CrossingWrapper.scala b/src/main/scala/coreplex/CrossingWrapper.scala index 6a7b3a93..e0b888be 100644 --- a/src/main/scala/coreplex/CrossingWrapper.scala +++ b/src/main/scala/coreplex/CrossingWrapper.scala @@ -24,9 +24,7 @@ trait HasCrossingHelper extends LazyScope val out = x.node.parentsOut.exists(_ eq this) // is the crossing exiting the wrapper? crossing match { case SynchronousCrossing(params) => { - // !!! Why does star resolution fail for tile with no slave devices? - // this { TLBuffer(params)(x.node) } - x.node + this { TLBuffer(params)(x.node) } } case RationalCrossing(direction) => { def sourceGen = LazyModule(new TLRationalCrossingSource) diff --git a/src/main/scala/coreplex/PeripheryBus.scala b/src/main/scala/coreplex/PeripheryBus.scala index c3a6939d..49f0b25b 100644 --- a/src/main/scala/coreplex/PeripheryBus.scala +++ b/src/main/scala/coreplex/PeripheryBus.scala @@ -37,15 +37,12 @@ class PeripheryBus(params: PeripheryBusParams)(implicit p: Parameters) extends T atomics.node } - def toTile( - adapt: TLOutwardNode => TLOutwardNode, - to: TLInwardNode, - name: Option[String] = None) { + def toTile(name: Option[String] = None)(gen: Parameters => TLInwardNode) { this { LazyScope(s"${busName}ToTile${name.getOrElse("")}") { SinkCardinality { implicit p => FlipRendering { implicit p => - to :*= adapt(outwardNode) + gen(p) :*= outwardNode } } } diff --git a/src/main/scala/coreplex/RocketCoreplex.scala b/src/main/scala/coreplex/RocketCoreplex.scala index d3f5859d..943edc73 100644 --- a/src/main/scala/coreplex/RocketCoreplex.scala +++ b/src/main/scala/coreplex/RocketCoreplex.scala @@ -28,18 +28,11 @@ case class TileMasterPortParams( .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)) - - 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) tile_master_blocker.foreach { _.controlNode := coreplex.pbus.toVariableWidthSlaves } - node.foreach { _ :=* masterNode } - - node.getOrElse(masterNode) + (Seq(tile_master_fixer.node) ++ TLBuffer.chain(addBuffers) + ++ tile_master_blocker.map(_.node) ++ tile_master_cork.map(_.node)) + .foldRight(masterNode)(_ :=* _) } } @@ -48,22 +41,16 @@ case class TileSlavePortParams( blockerCtrlAddr: Option[BigInt] = None) { def adapt(coreplex: HasPeripheryBus) - (masterNode: TLOutwardNode) - (implicit p: Parameters, sourceInfo: SourceInfo): TLOutwardNode = { + (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))) - val tile_slave_buffer = LazyModule(new TLBufferChain(addBuffers)) - - val node: Option[TLNode] = TLNodeChain(List( - Some(tile_slave_buffer.node), - tile_slave_blocker.map(_.node)).flatten) tile_slave_blocker.foreach { _.controlNode := coreplex.pbus.toVariableWidthSlaves } - node.foreach { _ :*= masterNode } - - node.getOrElse(masterNode) + (TLBuffer.chain(addBuffers) ++ tile_slave_blocker.map(_.node)) + .foldLeft(slaveNode)(_ :*= _) } } @@ -116,18 +103,10 @@ trait HasRocketTiles extends HasTiles ).suggestName(tp.name) // Connect the master ports of the tile to the system bus - sbus.fromTile( - adapt = {x: TLOutwardNode => wrapper.cross(x) } andThen - crossing.master.adapt(this) _, - from = wrapper.masterNode, - name = tp.name) + sbus.fromTile(tp.name) { implicit p => crossing.master.adapt(this)(wrapper.cross(wrapper.masterNode)) } // Connect the slave ports of the tile to the periphery bus - pbus.toTile( - adapt = {x: TLOutwardNode => wrapper.cross(x) } compose - crossing.slave.adapt(this) _, - to = wrapper.slaveNode, - name = tp.name) + pbus.toTile(tp.name) { implicit p => crossing.slave.adapt(this)(wrapper.slaveNode) } // !!! wrapper.cross // Handle all the different types of interrupts crossing to or from the tile: // 1. Debug interrupt is definitely asynchronous in all cases. diff --git a/src/main/scala/coreplex/SystemBus.scala b/src/main/scala/coreplex/SystemBus.scala index a87726a6..46820c76 100644 --- a/src/main/scala/coreplex/SystemBus.scala +++ b/src/main/scala/coreplex/SystemBus.scala @@ -52,14 +52,11 @@ class SystemBus(params: SystemBusParams)(implicit p: Parameters) extends TLBusWr def fromFrontBus: TLInwardNode = master_splitter.node - def fromTile( - adapt: TLOutwardNode => TLOutwardNode, - from: TLOutwardNode, - name: Option[String] = None) { + def fromTile(name: Option[String])(gen: Parameters => TLOutwardNode) { this { LazyScope(s"${busName}FromTile${name.getOrElse("")}") { SourceCardinality { implicit p => - master_splitter.node :=* adapt(from) + master_splitter.node :=* gen(p) } } } diff --git a/src/main/scala/groundtest/Coreplex.scala b/src/main/scala/groundtest/Coreplex.scala index d8eff447..73a37433 100644 --- a/src/main/scala/groundtest/Coreplex.scala +++ b/src/main/scala/groundtest/Coreplex.scala @@ -26,9 +26,7 @@ class GroundTestCoreplex(implicit p: Parameters) extends BaseCoreplex )} tiles.flatMap(_.dcacheOpt).foreach { dc => - sbus.fromTile( - adapt = TileMasterPortParams(addBuffers = 1).adapt(this) _, - from = dc.node) + sbus.fromTile(None) { implicit p => TileMasterPortParams(addBuffers = 1).adapt(this)(dc.node) } } val pbusRAM = LazyModule(new TLRAM(AddressSet(testRamAddr, 0xffff), true, false, pbus.beatBytes)) diff --git a/src/main/scala/tilelink/Buffer.scala b/src/main/scala/tilelink/Buffer.scala index ba7006e2..6026bde1 100644 --- a/src/main/scala/tilelink/Buffer.scala +++ b/src/main/scala/tilelink/Buffer.scala @@ -79,18 +79,9 @@ object TLBuffer } } -object TLNodeChain { - def apply(nodes: Seq[TLNode])(implicit p: Parameters): Option[TLNode] = if(nodes.size > 0) { - (nodes.init zip nodes.tail) foreach { case (prev, next) => next :=? prev } - Some(NodeHandle(nodes.head, nodes.last)) - } else { - None - } -} - class TLBufferChain(depth: Int)(implicit p: Parameters) extends SimpleLazyModule { val buf_chain = List.fill(depth)(LazyModule(new TLBuffer(BufferParams.default))) - val node = TLNodeChain(buf_chain.map(_.node)).getOrElse(TLIdentityNode()) + val node = buf_chain.map(_.node:TLNode).reduceOption(_ :=? _).getOrElse(TLIdentityNode()) } object TLBufferChain From 6276ea429166b5b8a5424f9a8cb04c13dc90e899 Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Wed, 25 Oct 2017 11:17:17 -0700 Subject: [PATCH 10/23] diplomacy: it possible for NodeHandles to put indirection on their attachment --- src/main/scala/diplomacy/Nodes.scala | 48 +++++++++++++++------------- 1 file changed, 25 insertions(+), 23 deletions(-) diff --git a/src/main/scala/diplomacy/Nodes.scala b/src/main/scala/diplomacy/Nodes.scala index 868fffee..a3266977 100644 --- a/src/main/scala/diplomacy/Nodes.scala +++ b/src/main/scala/diplomacy/Nodes.scala @@ -126,15 +126,15 @@ 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] = { inward.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] = { inward.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] = { inward.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] = { inward.bind(h, p(CardinalityInferenceDirectionKey)); 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_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] = { inward.bind(h, BIND_ONCE); this } - override def :*= (h: OutwardNodeHandle[DI, UI, BI])(implicit p: Parameters, sourceInfo: SourceInfo): OutwardNodeHandle[DO, UO, BO] = { inward.bind(h, BIND_STAR); this } - override def :=* (h: OutwardNodeHandle[DI, UI, BI])(implicit p: Parameters, sourceInfo: SourceInfo): OutwardNodeHandle[DO, UO, BO] = { inward.bind(h, BIND_QUERY); this } - override def :=? (h: OutwardNodeHandle[DI, UI, BI])(implicit p: Parameters, sourceInfo: SourceInfo): OutwardNodeHandle[DO, UO, BO] = { inward.bind(h, p(CardinalityInferenceDirectionKey)); this } + 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 @@ -152,18 +152,20 @@ case class NodeHandlePair[DI, UI, BI <: Data, DO, UO, BO <: Data] trait InwardNodeHandle[DI, UI, BI <: Data] extends NoHandle { - protected[diplomacy] val inward: InwardNode[DI, UI, BI] + 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] = { inward.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] = { inward.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] = { inward.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] = { inward.bind(h, p(CardinalityInferenceDirectionKey)); 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_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 = { inward.bind(h, BIND_ONCE); NoHandleObject } - def :*= (h: OutwardNodeHandle[DI, UI, BI])(implicit p: Parameters, sourceInfo: SourceInfo): NoHandle = { inward.bind(h, BIND_STAR); NoHandleObject } - def :=* (h: OutwardNodeHandle[DI, UI, BI])(implicit p: Parameters, sourceInfo: SourceInfo): NoHandle = { inward.bind(h, BIND_QUERY); NoHandleObject } - def :=? (h: OutwardNodeHandle[DI, UI, BI])(implicit p: Parameters, sourceInfo: SourceInfo): NoHandle = { inward.bind(h, p(CardinalityInferenceDirectionKey)); NoHandleObject } + 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 @@ -182,7 +184,7 @@ object NodeBinding 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}") @@ -206,18 +208,18 @@ trait InwardNode[DI, UI, BI <: Data] extends BaseNode with InwardNodeHandle[DI, protected[diplomacy] val iPortMapping: Seq[(Int, Int)] protected[diplomacy] val iParams: Seq[UI] - protected[diplomacy] def bind(h: OutwardNodeHandle[DI, UI, BI], binding: NodeBinding)(implicit p: Parameters, sourceInfo: SourceInfo): Unit + protected[diplomacy] def bind(h: OutwardNode[DI, UI, BI], binding: NodeBinding)(implicit p: Parameters, sourceInfo: SourceInfo): Unit } 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}") @@ -380,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 - protected[diplomacy] 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 From e30906589f949b3db75475ee69840150511bc132 Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Wed, 25 Oct 2017 14:45:44 -0700 Subject: [PATCH 11/23] coreplex: refactor crossings to use node pattern --- src/main/scala/coreplex/CrossingWrapper.scala | 178 +++++++++++------- src/main/scala/coreplex/RocketCoreplex.scala | 17 +- src/main/scala/interrupts/package.scala | 1 + src/main/scala/tile/RocketTile.scala | 2 +- 4 files changed, 115 insertions(+), 83 deletions(-) diff --git a/src/main/scala/coreplex/CrossingWrapper.scala b/src/main/scala/coreplex/CrossingWrapper.scala index e0b888be..0f956f74 100644 --- a/src/main/scala/coreplex/CrossingWrapper.scala +++ b/src/main/scala/coreplex/CrossingWrapper.scala @@ -15,80 +15,116 @@ case class SynchronousCrossing(params: BufferParams = BufferParams.default) exte case class RationalCrossing(direction: RationalDirection = FastToSlow) extends CoreplexClockCrossing case class AsynchronousCrossing(depth: Int, sync: Int = 3) extends CoreplexClockCrossing -trait HasCrossingHelper extends LazyScope +trait HasCrossingMethods extends LazyScope +{ + this: LazyModule => + + // TileLink + + def crossTLSyncInOut(out: Boolean)(params: BufferParams = BufferParams.default)(implicit p: Parameters): TLNode = { + this { LazyModule(new TLBuffer(params)).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 + 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 + 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) + } + + // 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 + 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 + 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 + 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 cross(x: TLCrossableNode): TLOutwardNode = { - val out = x.node.parentsOut.exists(_ eq this) // is the crossing exiting the wrapper? - crossing match { - case SynchronousCrossing(params) => { - this { TLBuffer(params)(x.node) } - } - case RationalCrossing(direction) => { - def sourceGen = LazyModule(new TLRationalCrossingSource) - def sinkGen = LazyModule(new TLRationalCrossingSink(direction)) - val source = if (out) this { sourceGen } else sourceGen - val sink = if (out) sinkGen else this { sinkGen } - source.node :=? x.node - sink.node :=? source.node - sink.node - } - case AsynchronousCrossing(depth, sync) => { - 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 } - source.node :=? x.node - sink.node :=? source.node - sink.node - } - } - } - - 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? - overrideCrossing.getOrElse(crossing) match { - case SynchronousCrossing(_) => { - 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 } - name.map(_ + "SyncSource").foreach(source.suggestName) - name.map(_ + "SyncSink").foreach(sink.suggestName) - source.node :=? x.node - sink.node :=? source.node - sink.node - } - case RationalCrossing(_) => { - 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 } - name.map(_ + "SyncSource").foreach(source.suggestName) - name.map(_ + "SyncSink").foreach(sink.suggestName) - source.node :=? x.node - sink.node :=? source.node - sink.node - } - case AsynchronousCrossing(_, sync) => { - 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 } - name.map(_ + "SyncSource").foreach(source.suggestName) - name.map(_ + "SyncSink").foreach(sink.suggestName) - source.node :=? x.node - sink.node :=? source.node - sink.node - } - } - } + def crossTLIn (implicit p: Parameters): TLNode = crossTLIn (crossing) + def crossTLOut (implicit p: Parameters): TLNode = crossTLOut (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 HasCrossingHelper +class CrossingWrapper(val crossing: CoreplexClockCrossing)(implicit p: Parameters) extends SimpleLazyModule with HasCrossing diff --git a/src/main/scala/coreplex/RocketCoreplex.scala b/src/main/scala/coreplex/RocketCoreplex.scala index 943edc73..667dfb72 100644 --- a/src/main/scala/coreplex/RocketCoreplex.scala +++ b/src/main/scala/coreplex/RocketCoreplex.scala @@ -49,7 +49,7 @@ case class TileSlavePortParams( .map(bp => LazyModule(new BasicBusBlocker(bp))) tile_slave_blocker.foreach { _.controlNode := coreplex.pbus.toVariableWidthSlaves } - (TLBuffer.chain(addBuffers) ++ tile_slave_blocker.map(_.node)) + (Seq() ++ tile_slave_blocker.map(_.node) ++ TLBuffer.chain(addBuffers)) .foldLeft(slaveNode)(_ :*= _) } } @@ -103,10 +103,10 @@ trait HasRocketTiles extends HasTiles ).suggestName(tp.name) // Connect the master ports of the tile to the system bus - sbus.fromTile(tp.name) { implicit p => crossing.master.adapt(this)(wrapper.cross(wrapper.masterNode)) } + sbus.fromTile(tp.name) { implicit p => crossing.master.adapt(this)(wrapper.crossTLOut :=* wrapper.masterNode) } // Connect the slave ports of the tile to the periphery bus - pbus.toTile(tp.name) { implicit p => crossing.slave.adapt(this)(wrapper.slaveNode) } // !!! wrapper.cross + pbus.toTile(tp.name) { implicit p => crossing.slave.adapt(this)(wrapper.slaveNode :*= wrapper.crossTLIn) } // Handle all the different types of interrupts crossing to or from the tile: // 1. Debug interrupt is definitely asynchronous in all cases. @@ -120,18 +120,13 @@ trait HasRocketTiles extends HasTiles 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) + wrapper.intXbar.intnode := wrapper.crossIntAsyncIn() := asyncIntXbar.intnode // 1. always crosses 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 - wrapper.intXbar.intnode := wrapper.cross( // 2. conditionally crosses - name = tp.name.map(_ + "PeriphIntXbar") - )(x = periphIntXbar.intnode) + wrapper.intXbar.intnode := wrapper.crossIntIn := periphIntXbar.intnode // 2. conditionally crosses val coreIntXbar = LazyModule(new IntXbar).suggestName(tp.name.map(_ + "CoreIntXbar")) lip.foreach { coreIntXbar.intnode := _ } // lip @@ -139,7 +134,7 @@ trait HasRocketTiles extends HasTiles wrapper.rocket.intOutputNode.foreach { i => // 4. conditionally crosses plic.intnode := FlipRendering { implicit p => - wrapper.cross(name = tp.name.map(_ + "PeriphIntOutput"))(x = i) + wrapper.crossIntIn := i } } diff --git a/src/main/scala/interrupts/package.scala b/src/main/scala/interrupts/package.scala index 9b2bef75..91b089db 100644 --- a/src/main/scala/interrupts/package.scala +++ b/src/main/scala/interrupts/package.scala @@ -9,6 +9,7 @@ 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] } diff --git a/src/main/scala/tile/RocketTile.scala b/src/main/scala/tile/RocketTile.scala index 7791c2d9..c253ba33 100644 --- a/src/main/scala/tile/RocketTile.scala +++ b/src/main/scala/tile/RocketTile.scala @@ -191,7 +191,7 @@ class RocketTileWrapper( params: RocketTileParams, val crossing: CoreplexClockCrossing, val boundaryBuffers: Boolean = false) - (implicit p: Parameters) extends BaseTile(params) with HasCrossingHelper { + (implicit p: Parameters) extends BaseTile(params) with HasCrossing { val rocket = LazyModule(new RocketTile(params)) From ce2b904b19746d22e1818eeb680fe9722eabb0ab Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Wed, 25 Oct 2017 16:13:55 -0700 Subject: [PATCH 12/23] coreplex: tidy up interrupt crossings --- src/main/scala/coreplex/RocketCoreplex.scala | 27 +++++++++----------- src/main/scala/devices/debug/Debug.scala | 8 +++--- 2 files changed, 16 insertions(+), 19 deletions(-) diff --git a/src/main/scala/coreplex/RocketCoreplex.scala b/src/main/scala/coreplex/RocketCoreplex.scala index 667dfb72..fc6546d5 100644 --- a/src/main/scala/coreplex/RocketCoreplex.scala +++ b/src/main/scala/coreplex/RocketCoreplex.scala @@ -118,24 +118,21 @@ trait HasRocketTiles extends HasTiles // 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.crossIntAsyncIn() := asyncIntXbar.intnode // 1. always crosses + wrapper.intXbar.intnode := wrapper { IntSyncCrossingSink(3) } := debug.intnode // 1. always async crossign - 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 - wrapper.intXbar.intnode := wrapper.crossIntIn := periphIntXbar.intnode // 2. conditionally crosses + // 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 - val coreIntXbar = LazyModule(new IntXbar).suggestName(tp.name.map(_ + "CoreIntXbar")) - lip.foreach { coreIntXbar.intnode := _ } // lip - wrapper.intXbar.intnode := coreIntXbar.intnode // 3. never crosses + lip.foreach { wrapper.intXbar.intnode := _ } // 3. lip never crosses - wrapper.rocket.intOutputNode.foreach { i => // 4. conditionally crosses - plic.intnode := FlipRendering { implicit p => - wrapper.crossIntIn := i - } + // From core to PLIC + wrapper.rocket.intOutputNode.foreach { i => // 4. conditional crossing + FlipRendering { implicit p => SourceCardinality { implicit p => + plic.intnode :=? wrapper.crossIntOut :=? i + } } } wrapper diff --git a/src/main/scala/devices/debug/Debug.scala b/src/main/scala/devices/debug/Debug.scala index f2d2a56f..68f45745 100644 --- a/src/main/scala/devices/debug/Debug.scala +++ b/src/main/scala/devices/debug/Debug.scala @@ -393,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) @@ -402,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() @@ -1040,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 @@ -1048,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) From 05d48d1807a8fe4a8073f21f796b53303c62ef78 Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Wed, 25 Oct 2017 16:30:07 -0700 Subject: [PATCH 13/23] TLBuffer: replace TLBufferChain with TLBuffer.chain --- src/main/scala/coreplex/FrontBus.scala | 12 ++++-------- src/main/scala/coreplex/SystemBus.scala | 4 +--- src/main/scala/tilelink/Buffer.scala | 18 ------------------ src/main/scala/tilelink/Bus.scala | 16 +++------------- 4 files changed, 8 insertions(+), 42 deletions(-) diff --git a/src/main/scala/coreplex/FrontBus.scala b/src/main/scala/coreplex/FrontBus.scala index 2ece4503..ce3e95f9 100644 --- a/src/main/scala/coreplex/FrontBus.scala +++ b/src/main/scala/coreplex/FrontBus.scala @@ -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 diff --git a/src/main/scala/coreplex/SystemBus.scala b/src/main/scala/coreplex/SystemBus.scala index 46820c76..138adc81 100644 --- a/src/main/scala/coreplex/SystemBus.scala +++ b/src/main/scala/coreplex/SystemBus.scala @@ -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 diff --git a/src/main/scala/tilelink/Buffer.scala b/src/main/scala/tilelink/Buffer.scala index 6026bde1..63c142c0 100644 --- a/src/main/scala/tilelink/Buffer.scala +++ b/src/main/scala/tilelink/Buffer.scala @@ -78,21 +78,3 @@ object TLBuffer buffers.map(_.node) } } - -class TLBufferChain(depth: Int)(implicit p: Parameters) extends SimpleLazyModule { - val buf_chain = List.fill(depth)(LazyModule(new TLBuffer(BufferParams.default))) - val node = buf_chain.map(_.node:TLNode).reduceOption(_ :=? _).getOrElse(TLIdentityNode()) -} - -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 - } - } -} diff --git a/src/main/scala/tilelink/Bus.scala b/src/main/scala/tilelink/Bus.scala index 5f2d018b..b078358b 100644 --- a/src/main/scala/tilelink/Bus.scala +++ b/src/main/scala/tilelink/Bus.scala @@ -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 From 380cc6f03ba7af2356d972277ef8ff70612829dc Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Wed, 25 Oct 2017 17:46:41 -0700 Subject: [PATCH 14/23] axi4: now also supports the island pattern --- src/main/scala/amba/axi4/package.scala | 3 +- src/main/scala/coreplex/CrossingWrapper.scala | 44 +++++++++++++++++-- 2 files changed, 42 insertions(+), 5 deletions(-) diff --git a/src/main/scala/amba/axi4/package.scala b/src/main/scala/amba/axi4/package.scala index af72e46f..cc5567bd 100644 --- a/src/main/scala/amba/axi4/package.scala +++ b/src/main/scala/amba/axi4/package.scala @@ -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] } diff --git a/src/main/scala/coreplex/CrossingWrapper.scala b/src/main/scala/coreplex/CrossingWrapper.scala index 0f956f74..1434c980 100644 --- a/src/main/scala/coreplex/CrossingWrapper.scala +++ b/src/main/scala/coreplex/CrossingWrapper.scala @@ -6,6 +6,7 @@ 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._ @@ -62,6 +63,38 @@ trait HasCrossingMethods extends LazyScope case x: RationalCrossing => crossTLRationalOut(x.direction) } + // AXI4 + + def crossAXI4SyncInOut(out: Boolean)(params: BufferParams = BufferParams.default)(implicit p: Parameters): AXI4Node = { + this { LazyModule(new AXI4Buffer(params)).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 + 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 = { @@ -119,10 +152,13 @@ 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 crossIntIn (implicit p: Parameters): IntNode = crossIntIn (crossing) - def crossIntOut(implicit p: Parameters): IntNode = crossIntOut(crossing) + 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) } From 76df1397e0ce65955663eee23979a8515e7ccd10 Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Wed, 25 Oct 2017 17:47:09 -0700 Subject: [PATCH 15/23] crossings: stop using deprecated APIs in tests --- src/main/scala/amba/axi4/AsyncCrossing.scala | 16 +++++----------- src/main/scala/tilelink/AsyncCrossing.scala | 16 +++++----------- src/main/scala/tilelink/Fuzzer.scala | 14 +------------- 3 files changed, 11 insertions(+), 35 deletions(-) diff --git a/src/main/scala/amba/axi4/AsyncCrossing.scala b/src/main/scala/amba/axi4/AsyncCrossing.scala index a394fa6b..2fe69353 100644 --- a/src/main/scala/amba/axi4/AsyncCrossing.scala +++ b/src/main/scala/amba/axi4/AsyncCrossing.scala @@ -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 { @@ -89,28 +90,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 } } diff --git a/src/main/scala/tilelink/AsyncCrossing.scala b/src/main/scala/tilelink/AsyncCrossing.scala index 3e9c5c2f..72ccc47f 100644 --- a/src/main/scala/tilelink/AsyncCrossing.scala +++ b/src/main/scala/tilelink/AsyncCrossing.scala @@ -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 { @@ -113,26 +114,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 } } diff --git a/src/main/scala/tilelink/Fuzzer.scala b/src/main/scala/tilelink/Fuzzer.scala index c2e6a769..55678fb8 100644 --- a/src/main/scala/tilelink/Fuzzer.scala +++ b/src/main/scala/tilelink/Fuzzer.scala @@ -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 } } From da7703aee9c52bdb0bf2ab1fb4197bb17b047c95 Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Thu, 26 Oct 2017 13:03:22 -0700 Subject: [PATCH 16/23] crossings: deprecate non-island crossing style --- src/main/scala/amba/axi4/AsyncCrossing.scala | 1 + src/main/scala/tilelink/AsyncCrossing.scala | 1 + src/main/scala/tilelink/RationalCrossing.scala | 1 + 3 files changed, 3 insertions(+) diff --git a/src/main/scala/amba/axi4/AsyncCrossing.scala b/src/main/scala/amba/axi4/AsyncCrossing.scala index 2fe69353..f582f665 100644 --- a/src/main/scala/amba/axi4/AsyncCrossing.scala +++ b/src/main/scala/amba/axi4/AsyncCrossing.scala @@ -62,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)) diff --git a/src/main/scala/tilelink/AsyncCrossing.scala b/src/main/scala/tilelink/AsyncCrossing.scala index 72ccc47f..60bb59cb 100644 --- a/src/main/scala/tilelink/AsyncCrossing.scala +++ b/src/main/scala/tilelink/AsyncCrossing.scala @@ -86,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)) diff --git a/src/main/scala/tilelink/RationalCrossing.scala b/src/main/scala/tilelink/RationalCrossing.scala index c448774d..a44bc8ce 100644 --- a/src/main/scala/tilelink/RationalCrossing.scala +++ b/src/main/scala/tilelink/RationalCrossing.scala @@ -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) From 2acff8d21f4adc0e7b328d414eb900fdd058d20f Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Thu, 26 Oct 2017 13:08:09 -0700 Subject: [PATCH 17/23] util: delete old long-deprecated crossing code --- src/main/scala/util/Crossing.scala | 115 ----------------------------- 1 file changed, 115 deletions(-) diff --git a/src/main/scala/util/Crossing.scala b/src/main/scala/util/Crossing.scala index f6bab310..7d238ab5 100644 --- a/src/main/scala/util/Crossing.scala +++ b/src/main/scala/util/Crossing.scala @@ -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) - } -} From e76e0f6dcec4ee38a1c263c071bc34d095bb606f Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Thu, 26 Oct 2017 13:11:47 -0700 Subject: [PATCH 18/23] interrupts: add debugstring to nodes to show sync depth in graphml --- src/main/scala/interrupts/Crossing.scala | 4 ++-- src/main/scala/interrupts/Nodes.scala | 10 ++++++++-- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/main/scala/interrupts/Crossing.scala b/src/main/scala/interrupts/Crossing.scala index 5c3f8568..d7f53a26 100644 --- a/src/main/scala/interrupts/Crossing.scala +++ b/src/main/scala/interrupts/Crossing.scala @@ -27,7 +27,7 @@ object IntSyncCrossingSource class IntSyncCrossingSource(alreadyRegistered: Boolean = false)(implicit p: Parameters) extends LazyModule { - val node = IntSyncSourceNode() + val node = IntSyncSourceNode(alreadyRegistered) lazy val module = new LazyModuleImp(this) { (node.in zip node.out) foreach { case ((in, edgeIn), (out, edgeOut)) => @@ -43,7 +43,7 @@ class IntSyncCrossingSource(alreadyRegistered: Boolean = false)(implicit p: Para class IntSyncCrossingSink(sync: Int = 3)(implicit p: Parameters) extends LazyModule { - val node = IntSyncSinkNode() + val node = IntSyncSinkNode(sync) lazy val module = new LazyModuleImp(this) { (node.in zip node.out) foreach { case ((in, edgeIn), (out, edgeOut)) => diff --git a/src/main/scala/interrupts/Nodes.scala b/src/main/scala/interrupts/Nodes.scala index 5f5f86b8..6b431cc2 100644 --- a/src/main/scala/interrupts/Nodes.scala +++ b/src/main/scala/interrupts/Nodes.scala @@ -51,12 +51,18 @@ object IntSyncImp extends SimpleNodeImp[IntSourcePortParameters, IntSinkPortPara case class IntSyncIdentityNode()(implicit valName: ValName) extends IdentityNode(IntSyncImp)() -case class IntSyncSourceNode()(implicit valName: ValName) +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()(implicit valName: ValName) +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}" +} From 9e33ccdb0511369584e564aeccb74424ea94dd34 Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Thu, 26 Oct 2017 13:52:34 -0700 Subject: [PATCH 19/23] rocket: clarify intent of boundaryBuffers and move to RocketTile --- src/main/scala/coreplex/RocketCoreplex.scala | 6 +-- src/main/scala/tile/RocketTile.scala | 39 ++++++++++++++------ 2 files changed, 30 insertions(+), 15 deletions(-) diff --git a/src/main/scala/coreplex/RocketCoreplex.scala b/src/main/scala/coreplex/RocketCoreplex.scala index fc6546d5..7cf9b155 100644 --- a/src/main/scala/coreplex/RocketCoreplex.scala +++ b/src/main/scala/coreplex/RocketCoreplex.scala @@ -57,8 +57,7 @@ case class TileSlavePortParams( case class RocketCrossingParams( crossingType: CoreplexClockCrossing = SynchronousCrossing(), master: TileMasterPortParams = TileMasterPortParams(), - slave: TileSlavePortParams = TileSlavePortParams(), - boundaryBuffers: Boolean = false) { + slave: TileSlavePortParams = TileSlavePortParams()) { def knownRatio: Option[Int] = crossingType match { case RationalCrossing(_) => Some(2) case _ => None @@ -92,8 +91,7 @@ trait HasRocketTiles extends HasTiles // in the global Parameters about the specific tile being built now val wrapper = LazyModule(new RocketTileWrapper( params = tp, - crossing = crossing.crossingType, - boundaryBuffers = crossing.boundaryBuffers + crossing = crossing.crossingType )(p.alterPartial { case TileKey => tp case BuildRoCC => tp.rocc diff --git a/src/main/scala/tile/RocketTile.scala b/src/main/scala/tile/RocketTile.scala index c253ba33..fbb0bf9c 100644 --- a/src/main/scala/tile/RocketTile.scala +++ b/src/main/scala/tile/RocketTile.scala @@ -22,7 +22,9 @@ case class RocketTileParams( 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) } @@ -189,23 +191,38 @@ class RocketTileWrapperBundle[+L <: RocketTileWrapper](_outer: L) extends BaseTi class RocketTileWrapper( params: RocketTileParams, - val crossing: CoreplexClockCrossing, - val boundaryBuffers: Boolean = false) + 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 = if (boundaryBuffers) { - masterBuffer.node :=* rocket.masterNode - masterBuffer.node - } else { rocket.masterNode } + 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 = DisableMonitors { implicit p => if (boundaryBuffers) { - rocket.slaveNode :*= slaveBuffer.node - slaveBuffer.node - } else { rocket.slaveNode } } + 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 From e2d6d4d7252a1e1c2c42444db0dd803f52059d17 Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Thu, 26 Oct 2017 15:02:21 -0700 Subject: [PATCH 20/23] diplomacy: eliminate bindings dead-code --- src/main/scala/diplomacy/LazyModule.scala | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/main/scala/diplomacy/LazyModule.scala b/src/main/scala/diplomacy/LazyModule.scala index e994f70f..1903dec7 100644 --- a/src/main/scala/diplomacy/LazyModule.scala +++ b/src/main/scala/diplomacy/LazyModule.scala @@ -11,7 +11,6 @@ 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 @@ -178,7 +177,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) } } From a060c37173538630c66e54d7f816852fc560498d Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Thu, 26 Oct 2017 15:08:06 -0700 Subject: [PATCH 21/23] diplomacy: expose the API to query a Node for its neighbours --- src/main/scala/diplomacy/Nodes.scala | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/scala/diplomacy/Nodes.scala b/src/main/scala/diplomacy/Nodes.scala index a3266977..7c4b0eb8 100644 --- a/src/main/scala/diplomacy/Nodes.scala +++ b/src/main/scala/diplomacy/Nodes.scala @@ -110,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 @@ -396,11 +396,11 @@ sealed abstract class MixedNode[DI, UI, EI, BI <: Data, DO, UO, EO, BO <: Data]( } // 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]( From 60284082e7b747f3b83e170e2721348c69a4eefb Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Thu, 26 Oct 2017 15:19:05 -0700 Subject: [PATCH 22/23] diplomacy: add a hook for injecting code into LazyModule.module scope --- src/main/scala/diplomacy/LazyModule.scala | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/scala/diplomacy/LazyModule.scala b/src/main/scala/diplomacy/LazyModule.scala index 1903dec7..48243e61 100644 --- a/src/main/scala/diplomacy/LazyModule.scala +++ b/src/main/scala/diplomacy/LazyModule.scala @@ -63,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) @@ -163,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:_*) From 1d8e539362001920e029d3b42d8ed7250330cc28 Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Thu, 26 Oct 2017 15:41:17 -0700 Subject: [PATCH 23/23] coreplex: confirm crossings actually cross the right boundary --- src/main/scala/coreplex/CrossingWrapper.scala | 34 ++++++++++++++++--- 1 file changed, 30 insertions(+), 4 deletions(-) diff --git a/src/main/scala/coreplex/CrossingWrapper.scala b/src/main/scala/coreplex/CrossingWrapper.scala index 1434c980..1b6f1a4d 100644 --- a/src/main/scala/coreplex/CrossingWrapper.scala +++ b/src/main/scala/coreplex/CrossingWrapper.scala @@ -16,14 +16,32 @@ case class SynchronousCrossing(params: BufferParams = BufferParams.default) exte case class RationalCrossing(direction: RationalDirection = FastToSlow) extends CoreplexClockCrossing case class AsynchronousCrossing(depth: Int, sync: Int = 3) extends CoreplexClockCrossing -trait HasCrossingMethods extends LazyScope +private case class CrossingCheck(out: Boolean, source: BaseNode, sink: BaseNode) + +trait HasCrossingMethods extends LazyModule with LazyScope { - this: LazyModule => + // 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 = { - this { LazyModule(new TLBuffer(params)).node } + 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 = { @@ -32,6 +50,7 @@ trait HasCrossingMethods extends LazyScope 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) } @@ -41,6 +60,7 @@ trait HasCrossingMethods extends LazyScope 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) } @@ -66,7 +86,9 @@ trait HasCrossingMethods extends LazyScope // AXI4 def crossAXI4SyncInOut(out: Boolean)(params: BufferParams = BufferParams.default)(implicit p: Parameters): AXI4Node = { - this { LazyModule(new AXI4Buffer(params)).node } + 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 = { @@ -75,6 +97,7 @@ trait HasCrossingMethods extends LazyScope 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) } @@ -103,6 +126,7 @@ trait HasCrossingMethods extends LazyScope 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) } @@ -112,6 +136,7 @@ trait HasCrossingMethods extends LazyScope 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) } @@ -121,6 +146,7 @@ trait HasCrossingMethods extends LazyScope 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) }