From b8098d18be3aa55d928eedfc109a7e7fa0d6310a Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Fri, 1 Dec 2017 18:28:37 -0800 Subject: [PATCH] =?UTF-8?q?diplomacy:=20remove=20the=20:=3D=3F=20operator?= =?UTF-8?q?=20in=20favour=20of=20magic=20:*=3D*=20(#1139)?= The reason for the :=? operator was for when you have an adapter chain whose direction of cardinality you could not know. We used explicit directives to tell these compositions which way to go. Unfortunately, that makes the API leaky. You think the chain of adapters is just one adapter, but you have to use strange Cardinality scopes to use it. That's just bad. The new :*=* just automagically figures it out from the graph. --- src/main/scala/coreplex/CrossingWrapper.scala | 12 ++-- src/main/scala/coreplex/FrontBus.scala | 8 +-- src/main/scala/coreplex/PeripheryBus.scala | 6 +- src/main/scala/coreplex/RocketCoreplex.scala | 8 +-- src/main/scala/coreplex/SystemBus.scala | 4 +- src/main/scala/diplomacy/Nodes.scala | 68 ++++++++++--------- src/main/scala/diplomacy/package.scala | 12 ---- src/main/scala/tilelink/Bus.scala | 4 +- 8 files changed, 54 insertions(+), 68 deletions(-) diff --git a/src/main/scala/coreplex/CrossingWrapper.scala b/src/main/scala/coreplex/CrossingWrapper.scala index b8955b75..f76b058c 100644 --- a/src/main/scala/coreplex/CrossingWrapper.scala +++ b/src/main/scala/coreplex/CrossingWrapper.scala @@ -55,7 +55,7 @@ trait HasCrossingMethods extends LazyModule with LazyScope lazy val asink = LazyModule(new TLAsyncCrossingSink(depth, sync)) val source = if (out) this { asource } else asource val sink = if (out) asink else this { asink } - sink.node :=? source.node + sink.node :*=* source.node checks = CrossingCheck(out, source.node, sink.node) :: checks NodeHandle(source.node, sink.node) } @@ -65,7 +65,7 @@ trait HasCrossingMethods extends LazyModule with LazyScope lazy val rsink = LazyModule(new TLRationalCrossingSink(if (out) direction else direction.flip)) val source = if (out) this { rsource } else rsource val sink = if (out) rsink else this { rsink } - sink.node :=? source.node + sink.node :*=* source.node checks = CrossingCheck(out, source.node, sink.node) :: checks NodeHandle(source.node, sink.node) } @@ -102,7 +102,7 @@ trait HasCrossingMethods extends LazyModule with LazyScope lazy val axi4asink = LazyModule(new AXI4AsyncCrossingSink(depth, sync)) val source = if (out) this { axi4asource } else axi4asource val sink = if (out) axi4asink else this { axi4asink } - sink.node :=? source.node + sink.node :*=* source.node checks = CrossingCheck(out, source.node, sink.node) :: checks NodeHandle(source.node, sink.node) } @@ -131,7 +131,7 @@ trait HasCrossingMethods extends LazyModule with LazyScope lazy val intssink = LazyModule(new IntSyncCrossingSink(0)) val source = if (out) this { intssource } else intssource val sink = if (out) intssink else this { intssink } - sink.node :=? source.node + sink.node :*=* source.node checks = CrossingCheck(out, source.node, sink.node) :: checks NodeHandle(source.node, sink.node) } @@ -141,7 +141,7 @@ trait HasCrossingMethods extends LazyModule with LazyScope lazy val intasink = LazyModule(new IntSyncCrossingSink(sync)) val source = if (out) this { intasource } else intasource val sink = if (out) intasink else this { intasink } - sink.node :=? source.node + sink.node :*=* source.node checks = CrossingCheck(out, source.node, sink.node) :: checks NodeHandle(source.node, sink.node) } @@ -151,7 +151,7 @@ trait HasCrossingMethods extends LazyModule with LazyScope lazy val intrsink = LazyModule(new IntSyncCrossingSink(1)) val source = if (out) this { intrsource } else intrsource val sink = if (out) intrsink else this { intrsink } - sink.node :=? source.node + sink.node :*=* source.node checks = CrossingCheck(out, source.node, sink.node) :: checks NodeHandle(source.node, sink.node) } diff --git a/src/main/scala/coreplex/FrontBus.scala b/src/main/scala/coreplex/FrontBus.scala index dc325701..adab063a 100644 --- a/src/main/scala/coreplex/FrontBus.scala +++ b/src/main/scala/coreplex/FrontBus.scala @@ -28,12 +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 = SourceCardinality { implicit p => - TLBuffer.chain(addBuffers).foldLeft(master_buffer.node:TLInwardNode)(_ :=? _) + def fromSyncPorts(addBuffers: Int = 0, name: Option[String] = None): TLInwardNode = { + TLBuffer.chain(addBuffers).foldLeft(master_buffer.node:TLInwardNode)(_ :=* _) } - def fromSyncMasters(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 = { + TLBuffer.chain(addBuffers).foldLeft(master_buffer.node:TLInwardNode)(_ :=* _) } def fromCoherentChip: TLInwardNode = inwardNode diff --git a/src/main/scala/coreplex/PeripheryBus.scala b/src/main/scala/coreplex/PeripheryBus.scala index 66af8ef4..7b56f1ec 100644 --- a/src/main/scala/coreplex/PeripheryBus.scala +++ b/src/main/scala/coreplex/PeripheryBus.scala @@ -39,10 +39,8 @@ class PeripheryBus(params: PeripheryBusParams)(implicit p: Parameters) extends T def toTile(name: Option[String] = None)(gen: Parameters => TLInwardNode) { this { LazyScope(s"${busName}ToTile${name.getOrElse("")}") { - SinkCardinality { implicit p => - FlipRendering { implicit p => - gen(p) :*= outwardNode - } + FlipRendering { implicit p => + gen(p) :*= outwardNode } } } diff --git a/src/main/scala/coreplex/RocketCoreplex.scala b/src/main/scala/coreplex/RocketCoreplex.scala index 8d9f6e94..2860a9fd 100644 --- a/src/main/scala/coreplex/RocketCoreplex.scala +++ b/src/main/scala/coreplex/RocketCoreplex.scala @@ -112,7 +112,7 @@ trait HasRocketTiles extends HasTiles wrapper.intXbar.intnode := wrapper { IntSyncCrossingSink(3) } := debug.intnode // 1. always async crossign // 2. clint+plic conditionak crossing - val periphIntNode = SourceCardinality { implicit p => wrapper.intXbar.intnode :=? wrapper.crossIntIn } + val periphIntNode = wrapper.intXbar.intnode :=* wrapper.crossIntIn periphIntNode := clint.intnode // msip+mtip periphIntNode := plic.intnode // meip if (tp.core.useVM) periphIntNode := plic.intnode // seip @@ -121,9 +121,9 @@ trait HasRocketTiles extends HasTiles // From core to PLIC wrapper.rocket.intOutputNode.foreach { i => // 4. conditional crossing - FlipRendering { implicit p => SourceCardinality { implicit p => - plic.intnode :=? wrapper.crossIntOut :=? i - } } + FlipRendering { implicit p => + plic.intnode :=* wrapper.crossIntOut :=* i + } } wrapper diff --git a/src/main/scala/coreplex/SystemBus.scala b/src/main/scala/coreplex/SystemBus.scala index 7bce33da..1f403d95 100644 --- a/src/main/scala/coreplex/SystemBus.scala +++ b/src/main/scala/coreplex/SystemBus.scala @@ -53,9 +53,7 @@ class SystemBus(params: SystemBusParams)(implicit p: Parameters) extends TLBusWr def fromTile(name: Option[String])(gen: Parameters => TLOutwardNode) { this { LazyScope(s"${busName}FromTile${name.getOrElse("")}") { - SourceCardinality { implicit p => - master_splitter.node :=* gen(p) - } + master_splitter.node :=* gen(p) } } } diff --git a/src/main/scala/diplomacy/Nodes.scala b/src/main/scala/diplomacy/Nodes.scala index b5ea1b4a..e41ed238 100644 --- a/src/main/scala/diplomacy/Nodes.scala +++ b/src/main/scala/diplomacy/Nodes.scala @@ -9,24 +9,6 @@ import freechips.rocketchip.util.HeterogeneousBag import scala.collection.mutable.ListBuffer import scala.util.matching._ -object CardinalityInferenceDirection { - val cases = Seq(SOURCE_TO_SINK, SINK_TO_SOURCE, NO_INFERENCE) - sealed trait T { - def flip = this match { - case SOURCE_TO_SINK => SINK_TO_SOURCE - case SINK_TO_SOURCE => SOURCE_TO_SINK - case NO_INFERENCE => NO_INFERENCE - } - } - - case object SOURCE_TO_SINK extends T - case object SINK_TO_SOURCE extends T - case object NO_INFERENCE extends T -} - -private case object CardinalityInferenceDirectionKey extends - Field[CardinalityInferenceDirection.T](CardinalityInferenceDirection.NO_INFERENCE) - case object MonitorsEnabled extends Field[Boolean](true) case object RenderFlipped extends Field[Boolean](false) @@ -113,6 +95,9 @@ abstract class BaseNode(implicit val valName: ValName) protected[diplomacy] def gco: Option[BaseNode] // greatest common outer def inputs: Seq[(BaseNode, RenderedEdge)] def outputs: Seq[(BaseNode, RenderedEdge)] + + protected[diplomacy] val sinkCard: Int + protected[diplomacy] val sourceCard: Int } object BaseNode @@ -130,12 +115,12 @@ trait NodeHandle[DI, UI, EI, BI <: Data, DO, UO, EO, BO <: Data] override def := [DX, UX, EX, BX <: Data, EY](h: NodeHandle[DX, UX, EX, BX, DI, UI, EY, BI])(implicit p: Parameters, sourceInfo: SourceInfo): NodeHandle[DX, UX, EX, BX, DO, UO, EO, BO] = { bind(h, BIND_ONCE); NodeHandle(h, this) } override def :*= [DX, UX, EX, BX <: Data, EY](h: NodeHandle[DX, UX, EX, BX, DI, UI, EY, BI])(implicit p: Parameters, sourceInfo: SourceInfo): NodeHandle[DX, UX, EX, BX, DO, UO, EO, BO] = { bind(h, BIND_STAR); NodeHandle(h, this) } override def :=* [DX, UX, EX, BX <: Data, EY](h: NodeHandle[DX, UX, EX, BX, DI, UI, EY, BI])(implicit p: Parameters, sourceInfo: SourceInfo): NodeHandle[DX, UX, EX, BX, DO, UO, EO, BO] = { bind(h, BIND_QUERY); NodeHandle(h, this) } - override def :=? [DX, UX, EX, BX <: Data, EY](h: NodeHandle[DX, UX, EX, BX, DI, UI, EY, BI])(implicit p: Parameters, sourceInfo: SourceInfo): NodeHandle[DX, UX, EX, BX, DO, UO, EO, BO] = { bind(h, p(CardinalityInferenceDirectionKey)); NodeHandle(h, this) } + override def :*=*[DX, UX, EX, BX <: Data, EY](h: NodeHandle[DX, UX, EX, BX, DI, UI, EY, BI])(implicit p: Parameters, sourceInfo: SourceInfo): NodeHandle[DX, UX, EX, BX, DO, UO, EO, BO] = { bind(h, BIND_FLEX); NodeHandle(h, this) } // connecting a full node with an output => an output override def := [EY](h: OutwardNodeHandle[DI, UI, EY, BI])(implicit p: Parameters, sourceInfo: SourceInfo): OutwardNodeHandle[DO, UO, EO, BO] = { bind(h, BIND_ONCE); this } override def :*= [EY](h: OutwardNodeHandle[DI, UI, EY, BI])(implicit p: Parameters, sourceInfo: SourceInfo): OutwardNodeHandle[DO, UO, EO, BO] = { bind(h, BIND_STAR); this } override def :=* [EY](h: OutwardNodeHandle[DI, UI, EY, BI])(implicit p: Parameters, sourceInfo: SourceInfo): OutwardNodeHandle[DO, UO, EO, BO] = { bind(h, BIND_QUERY); this } - override def :=? [EY](h: OutwardNodeHandle[DI, UI, EY, BI])(implicit p: Parameters, sourceInfo: SourceInfo): OutwardNodeHandle[DO, UO, EO, BO] = { bind(h, p(CardinalityInferenceDirectionKey)); this } + override def :*=*[EY](h: OutwardNodeHandle[DI, UI, EY, BI])(implicit p: Parameters, sourceInfo: SourceInfo): OutwardNodeHandle[DO, UO, EO, BO] = { bind(h, BIND_FLEX); this } } object NodeHandle @@ -164,27 +149,19 @@ trait InwardNodeHandle[DI, UI, EI, BI <: Data] extends NoHandle def := [DX, UX, EX, BX <: Data, EY](h: NodeHandle[DX, UX, EX, BX, DI, UI, EY, BI])(implicit p: Parameters, sourceInfo: SourceInfo): InwardNodeHandle[DX, UX, EX, BX] = { bind(h, BIND_ONCE); h } def :*= [DX, UX, EX, BX <: Data, EY](h: NodeHandle[DX, UX, EX, BX, DI, UI, EY, BI])(implicit p: Parameters, sourceInfo: SourceInfo): InwardNodeHandle[DX, UX, EX, BX] = { bind(h, BIND_STAR); h } def :=* [DX, UX, EX, BX <: Data, EY](h: NodeHandle[DX, UX, EX, BX, DI, UI, EY, BI])(implicit p: Parameters, sourceInfo: SourceInfo): InwardNodeHandle[DX, UX, EX, BX] = { bind(h, BIND_QUERY); h } - def :=? [DX, UX, EX, BX <: Data, EY](h: NodeHandle[DX, UX, EX, BX, DI, UI, EY, BI])(implicit p: Parameters, sourceInfo: SourceInfo): InwardNodeHandle[DX, UX, EX, BX] = { bind(h, p(CardinalityInferenceDirectionKey)); h } + def :*=*[DX, UX, EX, BX <: Data, EY](h: NodeHandle[DX, UX, EX, BX, DI, UI, EY, BI])(implicit p: Parameters, sourceInfo: SourceInfo): InwardNodeHandle[DX, UX, EX, BX] = { bind(h, BIND_FLEX); h } // connecting input node with output node => no node def := [EY](h: OutwardNodeHandle[DI, UI, EY, BI])(implicit p: Parameters, sourceInfo: SourceInfo): NoHandle = { bind(h, BIND_ONCE); NoHandleObject } def :*= [EY](h: OutwardNodeHandle[DI, UI, EY, BI])(implicit p: Parameters, sourceInfo: SourceInfo): NoHandle = { bind(h, BIND_STAR); NoHandleObject } def :=* [EY](h: OutwardNodeHandle[DI, UI, EY, BI])(implicit p: Parameters, sourceInfo: SourceInfo): NoHandle = { bind(h, BIND_QUERY); NoHandleObject } - def :=? [EY](h: OutwardNodeHandle[DI, UI, EY, BI])(implicit p: Parameters, sourceInfo: SourceInfo): NoHandle = { bind(h, p(CardinalityInferenceDirectionKey)); NoHandleObject } + def :*=*[EY](h: OutwardNodeHandle[DI, UI, EY, BI])(implicit p: Parameters, sourceInfo: SourceInfo): NoHandle = { bind(h, BIND_FLEX); NoHandleObject } } sealed trait NodeBinding 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 - } -} +case object BIND_FLEX extends NodeBinding trait InwardNode[DI, UI, BI <: Data] extends BaseNode { @@ -253,27 +230,51 @@ sealed abstract class MixedNode[DI, UI, EI, BI <: Data, DO, UO, EO, BO <: Data]( protected[diplomacy] def mapParamsD(n: Int, p: Seq[DI]): Seq[DO] protected[diplomacy] def mapParamsU(n: Int, p: Seq[UO]): Seq[UI] + protected[diplomacy] lazy val sinkCard = oBindings.count(_._3 == BIND_QUERY) + iBindings.count(_._3 == BIND_STAR) + protected[diplomacy] lazy val sourceCard = iBindings.count(_._3 == BIND_QUERY) + oBindings.count(_._3 == BIND_STAR) + protected[diplomacy] lazy val flexOffset = { // positive = sink cardinality; define 0 to be sink (both should work) + def DFS(v: BaseNode, visited: Set[BaseNode]): Set[BaseNode] = { + if (visited.contains(v)) { + visited + } else { + val flexes = oBindings.filter(_._3 == BIND_FLEX).map(_._2) ++ iBindings.filter(_._3 == BIND_FLEX).map(_._2) + flexes.foldLeft(visited + v)((sum, n) => DFS(n, sum)) + } + } + val flexSet = DFS(this, Set()) + val allSink = flexSet.map(_.sinkCard).sum + val allSource = flexSet.map(_.sourceCard).sum + require (flexSet.size == 1 || allSink == 0 || allSource == 0, + s"The nodes ${flexSet.map(_.name)} which are inter-connected by :*=* have ${allSink} :*= operators and ${allSource} :=* operators connected to them, making it impossible to determine cardinality inference direction.") + allSink - allSource + } + private var starCycleGuard = false protected[diplomacy] lazy val (oPortMapping, iPortMapping, oStar, iStar) = { try { if (starCycleGuard) throw StarCycleException() - val oStars = oBindings.filter { case (_,_,b,_,_) => b == BIND_STAR }.size - val iStars = iBindings.filter { case (_,_,b,_,_) => b == BIND_STAR }.size + starCycleGuard = true + val oStars = oBindings.count { case (_,_,b,_,_) => b == BIND_STAR || (b == BIND_FLEX && flexOffset < 0) } + val iStars = iBindings.count { case (_,_,b,_,_) => b == BIND_STAR || (b == BIND_FLEX && flexOffset >= 0) } val oKnown = oBindings.map { case (_, n, b, _, _) => b match { case BIND_ONCE => 1 + case BIND_FLEX => { if (flexOffset < 0) 0 else n.iStar } case BIND_QUERY => n.iStar case BIND_STAR => 0 }}.foldLeft(0)(_+_) val iKnown = iBindings.map { case (_, n, b, _, _) => b match { case BIND_ONCE => 1 + case BIND_FLEX => { if (flexOffset >= 0) 0 else n.oStar } case BIND_QUERY => n.oStar case BIND_STAR => 0 }}.foldLeft(0)(_+_) val (iStar, oStar) = resolveStar(iKnown, oKnown, iStars, oStars) val oSum = oBindings.map { case (_, n, b, _, _) => b match { case BIND_ONCE => 1 + case BIND_FLEX => { if (flexOffset < 0) oStar else n.iStar } case BIND_QUERY => n.iStar case BIND_STAR => oStar }}.scanLeft(0)(_+_) val iSum = iBindings.map { case (_, n, b, _, _) => b match { case BIND_ONCE => 1 + case BIND_FLEX => { if (flexOffset >= 0) iStar else n.oStar } case BIND_QUERY => n.oStar case BIND_STAR => iStar }}.scanLeft(0)(_+_) val oTotal = oSum.lastOption.getOrElse(0) @@ -385,6 +386,7 @@ sealed abstract class MixedNode[DI, UI, EI, BI <: Data, DO, UO, EO, BO <: Data]( val o = y.oPushed y.oPush(i, x, binding match { case BIND_ONCE => BIND_ONCE + case BIND_FLEX => BIND_FLEX case BIND_STAR => BIND_QUERY case BIND_QUERY => BIND_STAR }) x.iPush(o, y, binding) diff --git a/src/main/scala/diplomacy/package.scala b/src/main/scala/diplomacy/package.scala index b4b40f40..3f175f32 100644 --- a/src/main/scala/diplomacy/package.scala +++ b/src/main/scala/diplomacy/package.scala @@ -31,18 +31,6 @@ package object diplomacy } } - def SinkCardinality[T](body: Parameters => T)(implicit p: Parameters) = body(p.alterPartial { - case CardinalityInferenceDirectionKey => CardinalityInferenceDirection.SINK_TO_SOURCE - }) - def SourceCardinality[T](body: Parameters => T)(implicit p: Parameters) = body(p.alterPartial { - case CardinalityInferenceDirectionKey => CardinalityInferenceDirection.SOURCE_TO_SINK - }) - def UnaryCardinality[T](body: Parameters => T)(implicit p: Parameters) = body(p.alterPartial { - case CardinalityInferenceDirectionKey => CardinalityInferenceDirection.NO_INFERENCE - }) - def FlipCardinality[T](body: Parameters => T)(implicit p: Parameters) = body(p.alterPartial { - case CardinalityInferenceDirectionKey => p(CardinalityInferenceDirectionKey).flip - }) def EnableMonitors[T](body: Parameters => T)(implicit p: Parameters) = body(p.alterPartial { case MonitorsEnabled => true }) diff --git a/src/main/scala/tilelink/Bus.scala b/src/main/scala/tilelink/Bus.scala index 31ffba5e..02169b61 100644 --- a/src/main/scala/tilelink/Bus.scala +++ b/src/main/scala/tilelink/Bus.scala @@ -72,8 +72,8 @@ abstract class TLBusWrapper(params: TLBusParams, val busName: String)(implicit p def bufferToSlaves: TLOutwardNode = outwardBufNode - def toSyncSlaves(name: Option[String] = None, addBuffers: Int = 0): TLOutwardNode = SinkCardinality { implicit p => - TLBuffer.chain(addBuffers).foldRight(outwardBufNode)(_ :=? _) + def toSyncSlaves(name: Option[String] = None, addBuffers: Int = 0): TLOutwardNode = { + TLBuffer.chain(addBuffers).foldRight(outwardBufNode)(_ :*= _) } def toVariableWidthSlaves: TLOutwardNode = outwardFragNode