1
0

diplomacy: remove the :=? operator in favour of magic :*=* (#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.
This commit is contained in:
Wesley W. Terpstra 2017-12-01 18:28:37 -08:00 committed by GitHub
parent dedf396915
commit b8098d18be
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 54 additions and 68 deletions

View File

@ -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)
}

View File

@ -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

View File

@ -39,7 +39,6 @@ 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
}
@ -47,7 +46,6 @@ class PeripheryBus(params: PeripheryBusParams)(implicit p: Parameters) extends T
}
}
}
}
/** Provides buses that serve as attachment points,
* for use in traits that connect individual devices or external ports.

View File

@ -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

View File

@ -53,12 +53,10 @@ 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)
}
}
}
}
def fromSyncPorts(params: BufferParams = BufferParams.default, name: Option[String] = None): TLInwardNode = {
val buffer = LazyModule(new TLBuffer(params))

View File

@ -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)

View File

@ -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
})

View File

@ -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