diff --git a/.gitmodules b/.gitmodules
index fa1f58748f..d99c4e5fe5 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -7,3 +7,7 @@
[submodule "dependencies/chisel"]
path = dependencies/chisel
url = https://github.com/chipsalliance/chisel.git
+[submodule "dependencies/diplomacy"]
+ path = dependencies/diplomacy
+ url = https://github.com/chipsalliance/diplomacy.git
+ branch = lordspacehog/standalone_diplomacy
diff --git a/build.sc b/build.sc
index b19e7a8927..b17a7d69be 100644
--- a/build.sc
+++ b/build.sc
@@ -4,6 +4,7 @@ import mill.scalalib.publish._
import coursier.maven.MavenRepository
import $file.dependencies.hardfloat.common
import $file.dependencies.cde.common
+import $file.dependencies.diplomacy.common
import $file.dependencies.chisel.build
import $file.common
@@ -18,6 +19,7 @@ object v {
val mainargs = ivy"com.lihaoyi::mainargs:0.5.0"
val json4sJackson = ivy"org.json4s::json4s-jackson:4.0.5"
val scalaReflect = ivy"org.scala-lang:scala-reflect:${scala}"
+ val sourcecode = ivy"com.lihaoyi::sourcecode:0.3.1"
val sonatypesSnapshots = Seq(
MavenRepository("https://s01.oss.sonatype.org/content/repositories/snapshots")
)
@@ -79,6 +81,34 @@ trait CDE
override def millSourcePath = os.pwd / "dependencies" / "cde" / "cde"
}
+object diplomacy extends mill.define.Cross[Diplomacy](v.chiselCrossVersions.keys.toSeq)
+
+trait Diplomacy
+ extends millbuild.dependencies.diplomacy.common.DiplomacyModule
+ with RocketChipPublishModule
+ with Cross.Module[String] {
+
+ override def scalaVersion: T[String] = T(v.scala)
+
+ override def millSourcePath = os.pwd / "dependencies" / "diplomacy" / "diplomacy"
+
+ // dont use chisel from source
+ def chiselModule = None
+ def chiselPluginJar = None
+
+ // use chisel from ivy
+ def chiselIvy = Some(v.chiselCrossVersions(crossValue)._1)
+ def chiselPluginIvy = Some(v.chiselCrossVersions(crossValue)._2)
+
+ // use CDE from source untill published to sonatype
+ def cdeModule = Some(cde)
+
+ // no cde ivy currently published
+ def cdeIvy = None
+
+ def sourcecodeIvy = v.sourcecode
+}
+
object rocketchip extends Cross[RocketChip](v.chiselCrossVersions.keys.toSeq)
trait RocketChip
@@ -104,6 +134,10 @@ trait RocketChip
def cdeModule = cde
+ def diplomacyModule = diplomacy(crossValue)
+
+ def diplomacyIvy = None
+
def mainargsIvy = v.mainargs
def json4sJacksonIvy = v.json4sJackson
@@ -127,7 +161,6 @@ trait RocketChipPublishModule
override def publishVersion: T[String] = T("1.6-SNAPSHOT")
}
-
// Tests
trait Emulator extends Cross.Module2[String, String] {
val top: String = crossValue
diff --git a/common.sc b/common.sc
index 574f0ad431..e3f8445d9c 100644
--- a/common.sc
+++ b/common.sc
@@ -45,16 +45,20 @@ trait RocketChipModule
// should be cde/common.sc#CDEModule
def cdeModule: ScalaModule
+ def diplomacyModule: ScalaModule
+
+ def diplomacyIvy: Option[Dep]
+
def mainargsIvy: Dep
def json4sJacksonIvy: Dep
- override def moduleDeps = super.moduleDeps ++ Seq(macrosModule, hardfloatModule, cdeModule)
+ override def moduleDeps = super.moduleDeps ++ Seq(macrosModule, hardfloatModule, cdeModule, diplomacyModule)
override def ivyDeps = T(
super.ivyDeps() ++ Agg(
mainargsIvy,
- json4sJacksonIvy
- )
+ json4sJacksonIvy,
+ ) ++ diplomacyIvy
)
}
diff --git a/dependencies/diplomacy b/dependencies/diplomacy
new file mode 160000
index 0000000000..b4f93b7747
--- /dev/null
+++ b/dependencies/diplomacy
@@ -0,0 +1 @@
+Subproject commit b4f93b7747e59376e65e11d83982f5b865d7e6f6
diff --git a/src/main/scala/aop/Select.scala b/src/main/scala/aop/Select.scala
deleted file mode 100644
index 132b859ed1..0000000000
--- a/src/main/scala/aop/Select.scala
+++ /dev/null
@@ -1,121 +0,0 @@
-// See LICENSE.SiFive for license details.
-
-package freechips.rocketchip.aop
-
-import chisel3.Data
-import org.chipsalliance.cde.config.Parameters
-import freechips.rocketchip.diplomacy.{
- AnyMixedNode,
- BaseNode,
- InwardNode,
- LazyModule,
- MixedNode,
- OutwardNode,
-}
-
-/** Combinators for finding specific sets of [[LazyModule]]s/[[Node]]s.
- *
- * These can be used for e.g. finding specific TLBundles in a design and
- * placing monitors or annotating metadata.
- */
-object Select {
-
- /** Contains information about an inward edge of a node
- */
- case class InwardEdge[Bundle <: Data, EdgeInParams](
- params: Parameters,
- bundle: Bundle,
- edge: EdgeInParams,
- node: OutwardNode[_, _, Bundle],
- )
-
- /** Contains information about an outward edge of a node
- */
- case class OutwardEdge[Bundle <: Data, EdgeOutParams](
- params: Parameters,
- bundle: Bundle,
- edge: EdgeOutParams,
- node: InwardNode[_, _, Bundle],
- )
-
- /** Collects the [[InwardEdge]]s of a node. Defined as a separate method so
- * that the bundle/edge types can be set properly
- */
- private def getInwardEdges[BI <: Data, EI](node: MixedNode[_, _, EI, BI, _, _, _, _ <: Data]): Iterable[InwardEdge[BI, EI]] = {
- node.iPorts.zip(node.in).map {
- case ((_, node, params, _), (bundle, edge)) =>
- InwardEdge(params, bundle, edge, node)
- }
- }
-
- /** Applies the collect function to each [[InwardEdge]] of a node
- */
- def collectInwardEdges[T](node: BaseNode)(collect: PartialFunction[InwardEdge[_ <: Data, _], T]): Iterable[T] = {
- node match {
- case node: AnyMixedNode => getInwardEdges(node).collect(collect)
- case _ => Seq.empty
- }
- }
-
- /** Collects the [[OutwardEdge]]s of a node. Defined as a separate method so
- * that the bundle/edge types can be set properly
- */
- private def getOutwardEdges[BO <: Data, EO](node: MixedNode[_, _, _, _ <: Data, _, _, EO, BO]): Iterable[OutwardEdge[BO, EO]] = {
- node.oPorts.zip(node.out).map {
- case ((_, node, params, _), (bundle, edge)) =>
- OutwardEdge(params, bundle, edge, node)
- }
- }
-
- /** Applies the collect function to each [[OutardEdge]] of a node
- */
- def collectOutwardEdges[T](node: BaseNode)(collect: PartialFunction[OutwardEdge[_ <: Data, _], T]): Iterable[T] = {
- node match {
- case node: AnyMixedNode => getOutwardEdges(node).collect(collect)
- case _ => Seq.empty
- }
- }
-
- /** Applies the collect function to a [[LazyModule]] and recursively to all
- * of its children.
- */
- def collectDeep[T](lmod: LazyModule)(collect: PartialFunction[LazyModule, T]): Iterable[T] = {
- collect.lift(lmod) ++
- lmod.getChildren.flatMap { child =>
- collectDeep(child)(collect)
- }
- }
-
- /** Applies the collect function to a [[LazyModule]] and its children if the
- * filter function returns true. Stops recursing when the filter function
- * returns false. e.g.
- * for this hierarchy
- * A
- * / \
- * B C
- * / \ \
- * D E F
- *
- * the following select function
- * {{{
- * filterCollectDeep(A) {
- * case B => false
- * case _ => true
- * } { m =>
- * printl(m)
- * }
- * }}}
- *
- * will only print modules A, C, and F
- */
- def filterCollectDeep[T](lmod: LazyModule)(filter: LazyModule => Boolean)(collect: PartialFunction[LazyModule, T]): Iterable[T] = {
- if (filter(lmod)) {
- collect.lift(lmod) ++
- lmod.getChildren.flatMap { child =>
- filterCollectDeep(child)(filter)(collect)
- }
- } else {
- Iterable.empty
- }
- }
-}
diff --git a/src/main/scala/aop/package.scala b/src/main/scala/aop/package.scala
new file mode 100644
index 0000000000..a773e15355
--- /dev/null
+++ b/src/main/scala/aop/package.scala
@@ -0,0 +1,6 @@
+package freechips.rocketchip
+
+object aop {
+ @deprecated("aop has moved to the standalone diplomacy library.", "rocketchip 2.0.0")
+ val Select = _root_.org.chipsalliance.diplomacy.aop.Select
+}
diff --git a/src/main/scala/diplomacy/BundleBridge.scala b/src/main/scala/diplomacy/BundleBridge.scala
deleted file mode 100644
index 39ba091ac9..0000000000
--- a/src/main/scala/diplomacy/BundleBridge.scala
+++ /dev/null
@@ -1,206 +0,0 @@
-// See LICENSE.SiFive for license details.
-
-package freechips.rocketchip.diplomacy
-
-import chisel3._
-import chisel3.experimental.SourceInfo
-import chisel3.reflect.DataMirror
-import chisel3.reflect.DataMirror.internal.chiselTypeClone
-import org.chipsalliance.cde.config.Parameters
-import freechips.rocketchip.util.DataToAugmentedData
-
-case class BundleBridgeParams[T <: Data](genOpt: Option[() => T])
-
-case object BundleBridgeParams {
- def apply[T <: Data](gen: () => T): BundleBridgeParams[T] = BundleBridgeParams(Some(gen))
-}
-
-case class BundleBridgeEdgeParams[T <: Data](source: BundleBridgeParams[T], sink: BundleBridgeParams[T])
-
-class BundleBridgeImp[T <: Data]() extends SimpleNodeImp[BundleBridgeParams[T], BundleBridgeParams[T], BundleBridgeEdgeParams[T], T]
-{
- def edge(pd: BundleBridgeParams[T], pu: BundleBridgeParams[T], p: Parameters, sourceInfo: SourceInfo) = BundleBridgeEdgeParams(pd, pu)
- def bundle(e: BundleBridgeEdgeParams[T]): T = {
- val sourceOpt = e.source.genOpt.map(_())
- val sinkOpt = e.sink.genOpt.map(_())
- (sourceOpt, sinkOpt) match {
- case (None, None) =>
- throw new Exception("BundleBridge needs source or sink to provide bundle generator function")
- case (Some(a), None) => chiselTypeClone(a)
- case (None, Some(b)) => chiselTypeClone(b)
- case (Some(a), Some(b)) => {
- require(DataMirror.checkTypeEquivalence(a, b),
- s"BundleBridge requires doubly-specified source and sink generators to have equivalent Chisel Data types, but got \n$a\n vs\n$b")
- chiselTypeClone(a)
- }
- }
- }
- def render(e: BundleBridgeEdgeParams[T]) = RenderedEdge(colour = "#cccc00" /* yellow */)
-}
-
-case class BundleBridgeSink[T <: Data](genOpt: Option[() => T] = None)
- (implicit valName: ValName)
- extends SinkNode(new BundleBridgeImp[T])(Seq(BundleBridgeParams(genOpt)))
-{
- def bundle: T = in(0)._1
-
- private def inferOutput = bundle.getElements.forall { elt =>
- DataMirror.directionOf(elt) == ActualDirection.Unspecified
- }
-
- def makeIO()(implicit valName: ValName): T = {
- val io: T = IO(if (inferOutput) Output(chiselTypeOf(bundle)) else chiselTypeClone(bundle))
- io.suggestName(valName.name)
- io <> bundle
- io
- }
- def makeIO(name: String): T = makeIO()(ValName(name))
-}
-
-object BundleBridgeSink {
- def apply[T <: Data]()(implicit valName: ValName): BundleBridgeSink[T] = {
- BundleBridgeSink(None)
- }
-}
-
-case class BundleBridgeSource[T <: Data](genOpt: Option[() => T] = None)(implicit valName: ValName) extends SourceNode(new BundleBridgeImp[T])(Seq(BundleBridgeParams(genOpt)))
-{
- def bundle: T = out(0)._1
-
- private def inferInput = bundle.getElements.forall { elt =>
- DataMirror.directionOf(elt) == ActualDirection.Unspecified
- }
-
- def makeIO()(implicit valName: ValName): T = {
- val io: T = IO(if (inferInput) Input(chiselTypeOf(bundle)) else Flipped(chiselTypeClone(bundle)))
- io.suggestName(valName.name)
- bundle <> io
- io
- }
- def makeIO(name: String): T = makeIO()(ValName(name))
-
- private var doneSink = false
- def makeSink()(implicit p: Parameters) = {
- require (!doneSink, "Can only call makeSink() once")
- doneSink = true
- val sink = BundleBridgeSink[T]()
- sink := this
- sink
- }
-}
-
-object BundleBridgeSource {
- def apply[T <: Data]()(implicit valName: ValName): BundleBridgeSource[T] = {
- BundleBridgeSource(None)
- }
- def apply[T <: Data](gen: () => T)(implicit valName: ValName): BundleBridgeSource[T] = {
- BundleBridgeSource(Some(gen))
- }
-}
-
-case class BundleBridgeIdentityNode[T <: Data]()(implicit valName: ValName) extends IdentityNode(new BundleBridgeImp[T])()
-case class BundleBridgeEphemeralNode[T <: Data]()(implicit valName: ValName) extends EphemeralNode(new BundleBridgeImp[T])()
-
-object BundleBridgeNameNode {
- def apply[T <: Data](name: String) = BundleBridgeIdentityNode[T]()(ValName(name))
-}
-
-case class BundleBridgeNexusNode[T <: Data](default: Option[() => T] = None,
- inputRequiresOutput: Boolean = false) // when false, connecting a source does not mandate connecting a sink
- (implicit valName: ValName)
- extends NexusNode(new BundleBridgeImp[T])(
- dFn = seq => seq.headOption.getOrElse(BundleBridgeParams(default)),
- uFn = seq => seq.headOption.getOrElse(BundleBridgeParams(None)),
- inputRequiresOutput = inputRequiresOutput,
- outputRequiresInput = !default.isDefined)
-
-class BundleBridgeNexus[T <: Data](
- inputFn: Seq[T] => T,
- outputFn: (T, Int) => Seq[T],
- default: Option[() => T] = None,
- inputRequiresOutput: Boolean = false,
- override val shouldBeInlined: Boolean = true
-) (implicit p: Parameters) extends LazyModule
-{
- val node = BundleBridgeNexusNode[T](default, inputRequiresOutput)
-
- lazy val module = new Impl
- class Impl extends LazyRawModuleImp(this) {
- val defaultWireOpt = default.map(_())
- val inputs: Seq[T] = node.in.map(_._1)
- inputs.foreach { i => require(DataMirror.checkTypeEquivalence(i, inputs.head),
- s"${node.context} requires all inputs have equivalent Chisel Data types, but got\n$i\nvs\n${inputs.head}")
- }
- inputs.flatMap(_.getElements).foreach { elt => DataMirror.directionOf(elt) match {
- case ActualDirection.Output => ()
- case ActualDirection.Unspecified => ()
- case _ => require(false, s"${node.context} can only be used with Output-directed Bundles")
- } }
-
- val outputs: Seq[T] = if (node.out.size > 0) {
- val broadcast: T = if (inputs.size >= 1) inputFn(inputs) else defaultWireOpt.get
- outputFn(broadcast, node.out.size)
- } else { Nil }
-
- node.out.map(_._1).foreach { o => require(DataMirror.checkTypeEquivalence(o, outputs.head),
- s"${node.context} requires all outputs have equivalent Chisel Data types, but got\n$o\nvs\n${outputs.head}")
- }
-
- require(outputs.size == node.out.size,
- s"${node.context} outputFn must generate one output wire per edgeOut, but got ${outputs.size} vs ${node.out.size}")
-
- node.out.zip(outputs).foreach { case ((out, _), bcast) => out := bcast }
- }
-}
-
-object BundleBridgeNexus {
- def safeRegNext[T <: Data](x: T): T = {
- val reg = Reg(chiselTypeOf(x))
- reg := x
- reg
- }
-
- def requireOne[T <: Data](registered: Boolean)(seq: Seq[T]): T = {
- require(seq.size == 1, "BundleBroadcast default requires one input")
- if (registered) safeRegNext(seq.head) else seq.head
- }
-
- def orReduction[T <: Data](registered: Boolean)(seq: Seq[T]): T = {
- val x = seq.reduce((a,b) => (a.asUInt | b.asUInt).asTypeOf(seq.head))
- if (registered) safeRegNext(x) else x
- }
-
- def fillN[T <: Data](registered: Boolean)(x: T, n: Int): Seq[T] = Seq.fill(n) {
- if (registered) safeRegNext(x) else x
- }
-
- def apply[T <: Data](
- inputFn: Seq[T] => T = orReduction[T](false) _,
- outputFn: (T, Int) => Seq[T] = fillN[T](false) _,
- default: Option[() => T] = None,
- inputRequiresOutput: Boolean = false,
- shouldBeInlined: Boolean = true
- )(implicit p: Parameters): BundleBridgeNexusNode[T] = {
- val nexus = LazyModule(new BundleBridgeNexus[T](inputFn, outputFn, default, inputRequiresOutput, shouldBeInlined))
- nexus.node
- }
-}
-
-object BundleBroadcast {
- def apply[T <: Data](
- name: Option[String] = None,
- registered: Boolean = false,
- default: Option[() => T] = None,
- inputRequiresOutput: Boolean = false, // when false, connecting a source does not mandate connecting a sink
- shouldBeInlined: Boolean = true
- )(implicit p: Parameters): BundleBridgeNexusNode[T] = {
- val broadcast = LazyModule(new BundleBridgeNexus[T](
- inputFn = BundleBridgeNexus.requireOne[T](registered) _,
- outputFn = BundleBridgeNexus.fillN[T](registered) _,
- default = default,
- inputRequiresOutput = inputRequiresOutput,
- shouldBeInlined = shouldBeInlined))
- name.foreach(broadcast.suggestName(_))
- broadcast.node
- }
-}
diff --git a/src/main/scala/diplomacy/Clone.scala b/src/main/scala/diplomacy/Clone.scala
deleted file mode 100644
index 4e0b9209d6..0000000000
--- a/src/main/scala/diplomacy/Clone.scala
+++ /dev/null
@@ -1,37 +0,0 @@
-// See LICENSE.SiFive for license details.
-
-package freechips.rocketchip.diplomacy
-
-import chisel3._
-import chisel3.experimental.{CloneModuleAsRecord, SourceInfo}
-
-final class CloneLazyModule private (val base: LazyModule)
-{
- // Pay special attention to the .iParams and .oParams of the node, which
- // indicate the parameters a stand-in master must supply.
- def clone[DI, UI, EI, BI <: Data, DO, UO, EO, BO <: Data](node: NodeHandle[DI, UI, EI, BI, DO, UO, EO, BO])(implicit valName: ValName) =
- new MixedTestNode(node, this)
-
- protected[diplomacy] lazy val io = CloneModuleAsRecord(base.module)
-}
-
-object CloneLazyModule
-{
- /** The old API **/
- def apply(base: LazyModule) = new CloneLazyModule(base)
-
-
- /** Constructs a [[LazyModule]], but replaces its [[LazyModuleImp]] with a cloned [[LazyModuleImp]]
- * from another source. The user of [[CloneLazyModule]] must be careful to guarantee that
- * bc and cloneProto have equivalent [[LazyModuleImp]]'s.
- *
- * @param bc [[LazyModule]] instance to wrap, this instance will not evaluate its own [[LazyModuleImp]]
- * @param cloneProto [[LazyModule]] instance which will provide the [[LazyModuleImp]] implementation for bc
- */
- def apply[A <: LazyModule, B <: LazyModule](bc: A, cloneProto: B)(implicit valName: ValName, sourceInfo: SourceInfo): A = {
- require(LazyModule.scope.isDefined, s"CloneLazyModule ${bc.name} ${sourceLine(sourceInfo)} can only exist as the child of a parent LazyModule")
- LazyModule(bc)
- bc.cloneProto = Some(cloneProto)
- bc
- }
-}
diff --git a/src/main/scala/diplomacy/LazyModule.scala b/src/main/scala/diplomacy/LazyModule.scala
deleted file mode 100644
index ff6e037876..0000000000
--- a/src/main/scala/diplomacy/LazyModule.scala
+++ /dev/null
@@ -1,612 +0,0 @@
-// See LICENSE.SiFive for license details.
-
-package freechips.rocketchip.diplomacy
-
-import chisel3._
-import chisel3.{Module, RawModule, Reset, withClockAndReset}
-import chisel3.experimental.{ChiselAnnotation, CloneModuleAsRecord, SourceInfo, UnlocatableSourceInfo}
-import firrtl.passes.InlineAnnotation
-import org.chipsalliance.cde.config.Parameters
-
-import scala.collection.immutable.{SeqMap, SortedMap}
-import scala.util.matching._
-
-/** While the [[freechips.rocketchip.diplomacy]] package allows fairly abstract parameter negotiation while constructing a DAG,
- * [[LazyModule]] builds on top of the DAG annotated with the negotiated parameters and leverage's Scala's lazy evaluation property to split Chisel module generation into two phases:
- *
- * - Phase 1 (diplomatic) states parameters, hierarchy, and connections:
- * - [[LazyModule]] and [[BaseNode]] instantiation.
- * - [[BaseNode]] binding.
- * - Phase 2 (lazy) generates [[chisel3]] Modules:
- * - Parameters are negotiated across [[BaseNode]]s.
- * - Concrete [[Bundle]]s are created along [[BaseNode]]s and connected
- * - [[AutoBundle]] are automatically connected along [[Edges]], punching IO as necessary though module hierarchy
- * - [[LazyModuleImpLike]] generates [[chisel3.Module]]s.
- */
-abstract class LazyModule()(implicit val p: Parameters) {
- /** Contains sub-[[LazyModule]]s; can be accessed by [[getChildren]]. */
- protected[diplomacy] var children: List[LazyModule] = List[LazyModule]()
- /** Contains the [[BaseNode]]s instantiated within this instance. */
- protected[diplomacy] var nodes: List[BaseNode] = List[BaseNode]()
- /** Stores [[SourceInfo]] of this instance.
- *
- * The companion object factory method will set this to the correct value.
- */
- protected[diplomacy] var info: SourceInfo = UnlocatableSourceInfo
- /** Parent of this LazyModule. If this instance is at the top of the hierarchy, this will be [[None]]. */
- protected[diplomacy] val parent: Option[LazyModule] = LazyModule.scope
- /** If set, the LazyModule this LazyModule will be a clone of
- * Note that children of a cloned module will also have this set
- */
- protected[diplomacy] var cloneProto: Option[LazyModule] = None
-
- /** Code snippets from [[InModuleBody]] injection. */
- protected[diplomacy] var inModuleBody: List[() => Unit] = List[() => Unit]()
-
- /** Sequence of ancestor LazyModules, starting with [[parent]]. */
- def parents: Seq[LazyModule] = parent match {
- case None => Nil
- case Some(x) => x +: x.parents
- }
-
- // Push this instance onto the [[LazyModule.scope]] stack.
- LazyModule.scope = Some(this)
- parent.foreach(p => p.children = this :: p.children)
-
- /** Accumulates Some(names), taking the final one. `None`s are ignored. */
- private var suggestedNameVar: Option[String] = None
-
- /** Suggests instance name for [[LazyModuleImpLike]] module. */
- def suggestName(x: String): this.type = suggestName(Some(x))
-
- def suggestName(x: Option[String]): this.type = {
- x.foreach { n => suggestedNameVar = Some(n) }
- this
- }
-
- /** Finds the name of the first non-anonymous Scala class while walking up the class hierarchy. */
- private def findClassName(c: Class[_]): String = {
- val n = c.getName.split('.').last
- if (n.contains('$')) findClassName(c.getSuperclass) else n
- }
-
- /** Scala class name of this instance. */
- lazy val className: String = findClassName(getClass)
- /** Suggested instance name. Defaults to [[className]].*/
- lazy val suggestedName: String = suggestedNameVar.getOrElse(className)
- /** Suggested module name. Defaults to [[className]].*/
- lazy val desiredName: String = className // + hashcode?
-
- /** Return instance name. */
- def name: String = suggestedName // className + suggestedName ++ hashcode ?
- /** Return source line that defines this instance. */
- def line: String = sourceLine(info)
-
- // Accessing these names can only be done after circuit elaboration!
- /** Module name in verilog, used in GraphML.
- * For cloned lazyModules, this is the name of the prototype
- */
- lazy val moduleName: String = cloneProto.map(_.module.name).getOrElse(module.name)
- /** Hierarchical path of this instance, used in GraphML.
- * For cloned modules, construct this manually (since this.module should not be evaluated)
- */
- lazy val pathName: String = cloneProto.map(p => s"${parent.get.pathName}.${p.instanceName}")
- .getOrElse(module.pathName)
-
- /** Instance name in verilog. Should only be accessed after circuit elaboration. */
- lazy val instanceName: String = pathName.split('.').last
-
- /** [[chisel3]] hardware implementation of this [[LazyModule]].
- *
- * Subclasses should define this function as `lazy val`s for lazy evaluation.
- * Generally, the evaluation of this marks the beginning of phase 2.
- */
- def module: LazyModuleImpLike
-
- /** Recursively traverse all child LazyModules and Nodes of this LazyModule
- * to construct the set of empty [[Dangle]]'s that are this module's top-level IO
- * This is effectively doing the same thing as [[LazyModuleImp.instantiate]], but
- * without constructing any [[Module]]'s
- */
- protected[diplomacy] def cloneDangles(): List[Dangle] = {
- children.foreach(c => require(c.cloneProto.isDefined, s"${c.info}, ${c.parent.get.info}"))
- val childDangles = children.reverse.flatMap { c => c.cloneDangles() }
- val nodeDangles = nodes.reverse.flatMap(n => n.cloneDangles())
- val allDangles = nodeDangles ++ childDangles
- val pairing = SortedMap(allDangles.groupBy(_.source).toSeq: _*)
- val done = Set() ++ pairing.values.filter(_.size == 2).map {
- case Seq(a, b) =>
- require(a.flipped != b.flipped)
- a.source
- case _ =>
- None
- }
- val forward = allDangles.filter(d => !done(d.source))
- val dangles = forward.map { d =>
- d.copy(name = suggestedName + "_" + d.name)
- }
- dangles
- }
-
- /** Whether to omit generating the GraphML for this [[LazyModule]].
- *
- * Recursively checks whether all [[BaseNode]]s and children [[LazyModule]]s should omit GraphML
- * generation.
- */
- def omitGraphML: Boolean = nodes.forall(_.omitGraphML) && children.forall(_.omitGraphML)
-
- /** Whether this [[LazyModule]]'s module should be marked for in-lining by FIRRTL.
- *
- * The default heuristic is to inline any parents whose children have been inlined
- * and whose nodes all produce identity circuits.
- */
- def shouldBeInlined: Boolean = nodes.forall(_.circuitIdentity) && children.forall(_.shouldBeInlined)
-
- /** GraphML representation for this instance.
- *
- * This is a representation of the Nodes, Edges, LazyModule hierarchy,
- * and any other information that is added in by implementations.
- * It can be converted to an image with various third-party tools.
- */
- lazy val graphML: String = parent.map(_.graphML).getOrElse {
- val buf = new StringBuilder
- buf ++= "\n"
- buf ++= "\n"
- buf ++= " \n"
- buf ++= " \n"
- buf ++= " \n"
- buf ++= " \n"
- nodesGraphML(buf, " ")
- edgesGraphML(buf, " ")
- buf ++= " \n"
- buf ++= "\n"
- buf.toString
- }
-
- /** A globally unique [[LazyModule]] index for this instance. */
- private val index = {
- LazyModule.index = LazyModule.index + 1
- LazyModule.index
- }
-
- /** Generate GraphML fragment for nodes.
- *
- * @param buf String buffer to write to.
- * @param pad Padding as prefix for indentation purposes.
- */
- private def nodesGraphML(buf: StringBuilder, pad: String): Unit = {
- buf ++= s"""$pad\n"""
- buf ++= s"""$pad $instanceName\n"""
- buf ++= s"""$pad $moduleName ($pathName)\n"""
- buf ++= s"""$pad \n"""
- nodes.filter(!_.omitGraphML).foreach { n =>
- buf ++= s"""$pad \n"""
- buf ++= s"""$pad \n"""
- buf ++= s"""$pad ${n.formatNode}, \n${n.nodedebugstring}\n"""
- buf ++= s"""$pad \n"""
- }
- children.filter(!_.omitGraphML).foreach(_.nodesGraphML(buf, pad + " "))
- buf ++= s"""$pad \n"""
- buf ++= s"""$pad\n"""
- }
-
- /** Generate GraphML fragment for edges.
- *
- * @param buf String buffer to write to.
- * @param pad Padding as prefix for indentation purposes.
- */
- private def edgesGraphML(buf: StringBuilder, pad: String): Unit = {
- nodes.filter(!_.omitGraphML) foreach { n =>
- n.outputs.filter(!_._1.omitGraphML).foreach { case (o, edge) =>
- val RenderedEdge(colour, label, flipped) = edge
- buf ++= pad
- buf ++= """"
- } else {
- buf ++= s""" source=\"$index::${n.index}\""""
- buf ++= s""" target=\"${o.lazyModule.index}::${o.index}\">"""
- }
- buf ++= s""""""
- if (flipped) {
- buf ++= s""""""
- } else {
- buf ++= s""""""
- }
- buf ++= s""""""
- buf ++= s"""$label"""
- buf ++= s"""\n"""
- }
- }
- children.filter(!_.omitGraphML).foreach { c => c.edgesGraphML(buf, pad) }
- }
-
- /** Call function on all of this [[LazyModule]]'s [[children]].
- *
- * @param iterfunc Function to call on each descendant.
- */
- def childrenIterator(iterfunc: LazyModule => Unit): Unit = {
- iterfunc(this)
- children.foreach(_.childrenIterator(iterfunc))
- }
-
- /** Call function on all of this [[LazyModule]]'s [[nodes]].
- *
- * @param iterfunc Function to call on each descendant.
- */
- def nodeIterator(iterfunc: BaseNode => Unit): Unit = {
- nodes.foreach(iterfunc)
- childrenIterator(_.nodes.foreach(iterfunc))
- }
-
- /** Accessor for [[children]]. */
- def getChildren: List[LazyModule] = children
-
- /** Accessor for [[nodes]]. */
- def getNodes: List[BaseNode] = nodes
-}
-
-object LazyModule {
- /** Current [[LazyModule]] scope. The scope is a stack of [[LazyModule]]/[[LazyScope]]s.
- *
- * Each call to [[LazyScope.apply]] or [[LazyModule.apply]] will push that item onto the current scope.
- */
- protected[diplomacy] var scope: Option[LazyModule] = None
- /** Global index of [[LazyModule]]. Note that there is no zeroth module. */
- private var index = 0
-
- /** Wraps a [[LazyModule]], handling bookkeeping of scopes.
- *
- * This method manages the scope and index of the [[LazyModule]]s. All [[LazyModule]]s must be
- * wrapped exactly once.
- *
- * @param bc [[LazyModule]] instance to be wrapped.
- * @param valName [[ValName]] used to name this instance,
- * it can be automatically generated by [[ValName]] macro, or specified manually.
- * @param sourceInfo [[SourceInfo]] information about where this [[LazyModule]] is being generated
- */
- def apply[T <: LazyModule](bc: T)(implicit valName: ValName, sourceInfo: SourceInfo): T = {
- // Make sure the user puts [[LazyModule]] around modules in the correct order.
- require(scope.isDefined, s"LazyModule() applied to ${bc.name} twice ${sourceLine(sourceInfo)}. Ensure that descendant LazyModules are instantiated with the LazyModule() wrapper and that you did not call LazyModule() twice.")
- require(scope.get eq bc, s"LazyModule() applied to ${bc.name} before ${scope.get.name} ${sourceLine(sourceInfo)}")
- // Pop from the [[LazyModule.scope]] stack.
- scope = bc.parent
- bc.info = sourceInfo
- if (bc.suggestedNameVar.isEmpty) bc.suggestName(valName.name)
- bc
- }
-}
-
-/** Trait describing the actual [[Module]] implementation wrapped by a [[LazyModule]].
- *
- * This is the actual Chisel module that is lazily-evaluated in the second phase of Diplomacy.
- */
-sealed trait LazyModuleImpLike extends RawModule {
- /** [[LazyModule]] that contains this instance. */
- val wrapper: LazyModule
- /** IOs that will be automatically "punched" for this instance. */
- val auto: AutoBundle
- /** The metadata that describes the [[HalfEdge]]s which generated [[auto]]. */
- protected[diplomacy] val dangles: Seq[Dangle]
-
- // [[wrapper.module]] had better not be accessed while LazyModules are still being built!
- require(LazyModule.scope.isEmpty, s"${wrapper.name}.module was constructed before LazyModule() was run on ${LazyModule.scope.get.name}")
-
- /** Set module name. Defaults to the containing LazyModule's desiredName.*/
- override def desiredName: String = wrapper.desiredName
-
- suggestName(wrapper.suggestedName)
-
- /** [[Parameters]] for chisel [[Module]]s. */
- implicit val p: Parameters = wrapper.p
-
- /** instantiate this [[LazyModule]],
- * return [[AutoBundle]] and a unconnected [[Dangle]]s from this module and submodules. */
- protected[diplomacy] def instantiate(): (AutoBundle, List[Dangle]) = {
- // 1. It will recursively append [[wrapper.children]] into [[chisel3.internal.Builder]],
- // 2. return [[Dangle]]s from each module.
- val childDangles = wrapper.children.reverse.flatMap { c =>
- implicit val sourceInfo: SourceInfo = c.info
- c.cloneProto.map { cp =>
- // If the child is a clone, then recursively set cloneProto of its children as well
- def assignCloneProtos(bases: Seq[LazyModule], clones: Seq[LazyModule]): Unit = {
- require(bases.size == clones.size)
- (bases zip clones).map { case (l,r) =>
- require(l.getClass == r.getClass, s"Cloned children class mismatch ${l.name} != ${r.name}")
- l.cloneProto = Some(r)
- assignCloneProtos(l.children, r.children)
- }
- }
- assignCloneProtos(c.children, cp.children)
- // Clone the child module as a record, and get its [[AutoBundle]]
- val clone = CloneModuleAsRecord(cp.module).suggestName(c.suggestedName)
- val clonedAuto = clone("auto").asInstanceOf[AutoBundle]
- // Get the empty [[Dangle]]'s of the cloned child
- val rawDangles = c.cloneDangles()
- require(rawDangles.size == clonedAuto.elements.size)
- // Assign the [[AutoBundle]] fields of the cloned record to the empty [[Dangle]]'s
- val dangles = (rawDangles zip clonedAuto.elements).map { case (d, (_, io)) =>
- d.copy(dataOpt = Some(io))
- }
- dangles
- } .getOrElse {
- // For non-clones, instantiate the child module
- val mod = Module(c.module)
- mod.dangles
- }
- }
-
- // Ask each node in this [[LazyModule]] to call [[BaseNode.instantiate]].
- // This will result in a sequence of [[Dangle]] from these [[BaseNode]]s.
- val nodeDangles = wrapper.nodes.reverse.flatMap(_.instantiate())
- // Accumulate all the [[Dangle]]s from this node and any accumulated from its [[wrapper.children]]
- val allDangles = nodeDangles ++ childDangles
- // Group [[allDangles]] by their [[source]].
- val pairing = SortedMap(allDangles.groupBy(_.source).toSeq: _*)
- // For each [[source]] set of [[Dangle]]s of size 2, ensure that these
- // can be connected as a source-sink pair (have opposite flipped value).
- // Make the connection and mark them as [[done]].
- val done = Set() ++ pairing.values.filter(_.size == 2).map {
- case Seq(a, b) =>
- require(a.flipped != b.flipped)
- // @todo <> in chisel3 makes directionless connection.
- if (a.flipped) {
- a.data <> b.data
- } else {
- b.data <> a.data
- }
- a.source
- case _ =>
- None
- }
- // Find all [[Dangle]]s which are still not connected. These will end up as [[AutoBundle]] [[IO]] ports on the module.
- val forward = allDangles.filter(d => !done(d.source))
- // Generate [[AutoBundle]] IO from [[forward]].
- val auto = IO(new AutoBundle(forward.map { d => (d.name, d.data, d.flipped) }: _*))
- // Pass the [[Dangle]]s which remained and were used to generate the [[AutoBundle]] I/O ports up to the [[parent]] [[LazyModule]]
- val dangles = (forward zip auto.elements) map { case (d, (_, io)) =>
- if (d.flipped) {
- d.data <> io
- } else {
- io <> d.data
- }
- d.copy(dataOpt = Some(io), name = wrapper.suggestedName + "_" + d.name)
- }
- // Push all [[LazyModule.inModuleBody]] to [[chisel3.internal.Builder]].
- wrapper.inModuleBody.reverse.foreach {
- _ ()
- }
-
- if (wrapper.shouldBeInlined) {
- chisel3.experimental.annotate(new ChiselAnnotation {
- def toFirrtl = InlineAnnotation(toNamed)
- })
- }
-
- // Return [[IO]] and [[Dangle]] of this [[LazyModuleImp]].
- (auto, dangles)
- }
-}
-
-/** Actual description of a [[Module]] which can be instantiated by a call to [[LazyModule.module]].
- *
- * @param wrapper the [[LazyModule]] from which the `.module` call is being made.
- */
-class LazyModuleImp(val wrapper: LazyModule) extends Module with LazyModuleImpLike {
- /** Instantiate hardware of this `Module`. */
- val (auto, dangles) = instantiate()
-}
-
-/** Actual description of a [[RawModule]] which can be instantiated by a call to [[LazyModule.module]].
- *
- * @param wrapper the [[LazyModule]] from which the `.module` call is being made.
- */
-class LazyRawModuleImp(val wrapper: LazyModule) extends RawModule with LazyModuleImpLike {
- // These wires are the default clock+reset for all LazyModule children.
- // It is recommended to drive these even if you manually drive the [[clock]] and [[reset]] of all of the
- // [[LazyRawModuleImp]] children.
- // Otherwise, anonymous children ([[Monitor]]s for example) will not have their [[clock]] and/or [[reset]] driven properly.
- /** drive clock explicitly. */
- val childClock: Clock = Wire(Clock())
- /** drive reset explicitly. */
- val childReset: Reset = Wire(Reset())
- // the default is that these are disabled
- childClock := false.B.asClock
- childReset := chisel3.DontCare
-
- def provideImplicitClockToLazyChildren: Boolean = false
- val (auto, dangles) = if (provideImplicitClockToLazyChildren) {
- withClockAndReset(childClock, childReset) { instantiate() }
- } else {
- instantiate()
- }
-}
-
-/** Used for a [[LazyModule]] which does not need to define any [[LazyModuleImp]] implementation.
- *
- * It can be used as wrapper that only instantiates and connects [[LazyModule]]s.
- */
-class SimpleLazyModule(implicit p: Parameters) extends LazyModule {
- lazy val module = new LazyModuleImp(this)
-}
-class SimpleLazyRawModule(implicit p: Parameters) extends LazyModule {
- lazy val module = new LazyRawModuleImp(this)
-}
-
-
-/** Allows dynamic creation of [[Module]] hierarchy and "shoving" logic into a [[LazyModule]]. */
-trait LazyScope {
- this: LazyModule =>
- override def toString: String = s"LazyScope named $name"
-
- /** Evaluate `body` in the current [[LazyModule.scope]] */
- def apply[T](body: => T): T = {
- // Preserve the previous value of the [[LazyModule.scope]], because when calling [[apply]] function,
- // [[LazyModule.scope]] will be altered.
- val saved = LazyModule.scope
- // [[LazyModule.scope]] stack push.
- LazyModule.scope = Some(this)
- // Evaluate [[body]] in the current `scope`, saving the result to [[out]].
- val out = body
- // Check that the `scope` after evaluating `body` is the same as when we started.
- require(LazyModule.scope.isDefined, s"LazyScope $name tried to exit, but scope was empty!")
- require(LazyModule.scope.get eq this, s"LazyScope $name exited before LazyModule ${LazyModule.scope.get.name} was closed")
- // [[LazyModule.scope]] stack pop.
- LazyModule.scope = saved
- out
- }
-}
-
-/** Used to automatically create a level of module hierarchy (a [[SimpleLazyModule]]) within which [[LazyModule]]s can be instantiated and connected.
- *
- * It will instantiate a [[SimpleLazyModule]] to manage evaluation of `body` and evaluate `body` code snippets in this scope.
- */
-object LazyScope {
- /** Create a [[LazyScope]] with an implicit instance name.
- *
- * @param body code executed within the generated [[SimpleLazyModule]].
- * @param valName instance name of generated [[SimpleLazyModule]].
- * @param p [[Parameters]] propagated to [[SimpleLazyModule]].
- */
- def apply[T](body: => T)(implicit valName: ValName, p: Parameters): T = {
- apply(valName.name, "SimpleLazyModule", None)(body)(p)
- }
-
- /** Create a [[LazyScope]] with an explicitly defined instance name.
- *
- * @param name instance name of generated [[SimpleLazyModule]].
- * @param body code executed within the generated `SimpleLazyModule`
- * @param p [[Parameters]] propagated to [[SimpleLazyModule]].
- */
- def apply[T](name: String)(body: => T)(implicit p: Parameters): T = {
- apply(name, "SimpleLazyModule", None)(body)(p)
- }
-
- /** Create a [[LazyScope]] with an explicit instance and class name, and control inlining.
- *
- * @param name instance name of generated [[SimpleLazyModule]].
- * @param desiredModuleName class name of generated [[SimpleLazyModule]].
- * @param overrideInlining tell FIRRTL that this [[SimpleLazyModule]]'s module should be inlined.
- * @param body code executed within the generated `SimpleLazyModule`
- * @param p [[Parameters]] propagated to [[SimpleLazyModule]].
- */
- def apply[T](
- name: String,
- desiredModuleName: String,
- overrideInlining: Option[Boolean] = None)
- (body: => T)
- (implicit p: Parameters): T =
- {
- val scope = LazyModule(new SimpleLazyModule with LazyScope {
- override lazy val desiredName = desiredModuleName
- override def shouldBeInlined = overrideInlining.getOrElse(super.shouldBeInlined)
- }).suggestName(name)
- scope {
- body
- }
- }
-
- /** Create a [[LazyScope]] to temporarily group children for some reason, but tell Firrtl to inline it.
- *
- * For example, we might want to control a set of children's clocks but then not keep the parent wrapper.
- *
- * @param body code executed within the generated `SimpleLazyModule`
- * @param p [[Parameters]] propagated to [[SimpleLazyModule]].
- */
- def inline[T](body: => T)(implicit p: Parameters): T = {
- apply("noname", "ShouldBeInlined", Some(false))(body)(p)
- }
-}
-
-/** One side metadata of a [[Dangle]].
- *
- * Describes one side of an edge going into or out of a [[BaseNode]].
- *
- * @param serial the global [[BaseNode.serial]] number of the [[BaseNode]] that this [[HalfEdge]] connects to.
- * @param index the `index` in the [[BaseNode]]'s input or output port list that this [[HalfEdge]] belongs to.
- */
-case class HalfEdge(serial: Int, index: Int) extends Ordered[HalfEdge] {
-
- import scala.math.Ordered.orderingToOrdered
-
- def compare(that: HalfEdge): Int = HalfEdge.unapply(this) compare HalfEdge.unapply(that)
-}
-
-/** [[Dangle]] captures the `IO` information of a [[LazyModule]] and which two [[BaseNode]]s the [[Edges]]/[[Bundle]] connects.
- *
- * [[Dangle]]s are generated by [[BaseNode.instantiate]]
- * using [[MixedNode.danglesOut]] and [[MixedNode.danglesIn]] ,
- * [[LazyModuleImp.instantiate]] connects those that go to internal or explicit IO connections
- * in a [[LazyModule]].
- *
- * @param source the source [[HalfEdge]] of this [[Dangle]], which captures the source [[BaseNode]] and the port `index` within that [[BaseNode]].
- * @param sink sink [[HalfEdge]] of this [[Dangle]], which captures the sink [[BaseNode]] and the port `index` within that [[BaseNode]].
- * @param flipped flip or not in [[AutoBundle.makeElements]]. If true this corresponds to `danglesOut`, if false it corresponds to `danglesIn`.
- * @param dataOpt actual [[Data]] for the hardware connection. Can be empty if this belongs to a cloned module
- */
-case class Dangle(source: HalfEdge, sink: HalfEdge, flipped: Boolean, name: String, dataOpt: Option[Data]) {
- def data = dataOpt.get
-}
-
-/** [[AutoBundle]] will construct the [[Bundle]]s for a [[LazyModule]] in [[LazyModuleImpLike.instantiate]],
- *
- * @param elts is a sequence of data containing for each IO port a tuple of (name, data, flipped), where
- * name: IO name
- * data: actual data for connection.
- * flipped: flip or not in [[makeElements]]
- */
-final class AutoBundle(elts: (String, Data, Boolean)*) extends Record {
- // We need to preserve the order of elts, despite grouping by name to disambiguate things.
- val elements: SeqMap[String, Data] = SeqMap() ++ elts.zipWithIndex.map(makeElements).groupBy(_._1).values.flatMap {
- // If name is unique, it will return a Seq[index -> (name -> data)].
- case Seq((key, element, i)) => Seq(i -> (key -> element))
- // If name is not unique, name will append with j, and return `Seq[index -> (s"${name}_${j}" -> data)]`.
- case seq => seq.zipWithIndex.map { case ((key, element, i), j) => i -> (key + "_" + j -> element) }
- }.toList.sortBy(_._1).map(_._2)
- require(elements.size == elts.size)
-
- // Trim final "(_[0-9]+)*$" in the name, flip data with flipped.
- private def makeElements(tuple: ((String, Data, Boolean), Int)) = {
- val ((key, data, flip), i) = tuple
- // Trim trailing _0_1_2 stuff so that when we append _# we don't create collisions.
- val regex = new Regex("(_[0-9]+)*$")
- val element = if (flip) Flipped(data.cloneType) else data.cloneType
- (regex.replaceAllIn(key, ""), element, i)
- }
-}
-
-trait ModuleValue[T] {
- def getWrappedValue: T
-}
-
-/** Used to inject code snippets to be evaluated in [[LazyModuleImp.instantiate]] in the current [[LazyModule.scope]].
- *
- * It can be used to create additional hardware outside of the [[LazyModule.children]],
- * connections other than the internal [[BaseNode]] connections,
- * or additional IOs aside from the [[AutoBundle]]
- */
-object InModuleBody {
- def apply[T](body: => T): ModuleValue[T] = {
- require(LazyModule.scope.isDefined, s"InModuleBody invoked outside a LazyModule")
- val scope = LazyModule.scope.get
- // a wrapper to [[body]], being able to extract result after `execute`.
- val out = new ModuleValue[T] {
- var result: Option[T] = None
-
- def execute(): Unit = {
- result = Some(body)
- }
-
- def getWrappedValue: T = {
- require(result.isDefined, s"InModuleBody contents were requested before module was evaluated!")
- result.get
- }
- }
-
- // Prepend [[out.execute]] to [[scope.inModuleBody]],
- // it is a val with type of `() => Unit`, which will be executed in [[LazyModuleImp.instantiate]].
- scope.inModuleBody = out.execute _ +: scope.inModuleBody
- out
- }
-}
diff --git a/src/main/scala/diplomacy/Nodes.scala b/src/main/scala/diplomacy/Nodes.scala
deleted file mode 100644
index 51d3b7e92a..0000000000
--- a/src/main/scala/diplomacy/Nodes.scala
+++ /dev/null
@@ -1,1800 +0,0 @@
-// See LICENSE.SiFive for license details.
-
-package freechips.rocketchip.diplomacy
-
-import chisel3._
-import chisel3.experimental.SourceInfo
-import org.chipsalliance.cde.config.{Field, Parameters}
-import freechips.rocketchip.util.HeterogeneousBag
-
-import scala.collection.immutable
-import scala.collection.mutable.ListBuffer
-
-/** A field available in [[Parameters]] used to determine whether [[InwardNodeImp.monitor]] will be called. */
-case object MonitorsEnabled extends Field[Boolean](true)
-
-/** When rendering the edge in a graphical format, flip the order in which the edges' source and sink are presented.
- *
- * For example, when rendering graphML, yEd by default tries to put the source node vertically above the sink node, but
- * [[RenderFlipped]] inverts this relationship. When a particular [[LazyModule]] contains both source nodes and sink nodes,
- * flipping the rendering of one node's edge will usual produce a more concise visual layout for the [[LazyModule]].
- */
-case object RenderFlipped extends Field[Boolean](false)
-
-/** [[RenderedEdge]] can set the color and label of the visualization of the DAG. */
-case class RenderedEdge(
- colour: String,
- label: String = "",
- flipped: Boolean = false)
-
-/** [[InwardNodeImp]] defines the types that describe the inward side of the [[BaseNode]].
- *
- * @tparam DI The type of the downward-flowing parameters received on the inner side of the node.
- * @tparam UI The type of the upward-flowing parameters generated by the inner side of the node.
- * @tparam EI The type of the diplomatically-resolved parameters for an Edge connected to the inner side of the node.
- * @tparam BI The type of the [[chisel3.Data]] (usually a [[chisel3.Bundle]]) used when connecting to the inner side of the node,
- * corresponding to the real hardware interface that is emitted along the graph edge,
- * generally parameterized by the [[EI]] type.
- */
-trait InwardNodeImp[DI, UI, EI, BI <: Data]
-{
- /** Creates the inward edge parameters by combining the downward-flowing and upward-flowing parameters for edges
- * that connect to the inward side of this [[BaseNode]].
- *
- * It is left up to a user defining a particular protocol implementation to decide how the parameters flowing through
- * the graph in both directions on this Edge are combined into a single representation.
- *
- * @param pd The downward-flowing parameters into the node along the edge.
- * @param pu The upward-flowing parameters going out of the node along the edge.
- * @param p A view of [[Parameters]] at the point at which the returned edge is being bound.
- * @param sourceInfo [[SourceInfo]] of this edge.
- * @return An inward edge of this node.
- */
- def edgeI(pd: DI, pu: UI, p: Parameters, sourceInfo: SourceInfo): EI
-
- /** Create an inward bundle parameterized by the inward edge.
- *
- * @param ei Inward edge of this node.
- * @return An outward Bundle of this node parameterized by the negotiated Edge parameters.
- */
- def bundleI(ei: EI): BI
-
- /** Defines how input parameters can be "mixed" or negotiated together.
- *
- * The default behavior is to just return `pu`.
- *
- * @param pu The upward-flowing parameters going out of the node along the edge.
- * @param node An inward node to "mix" the upward-flowing parameters into.
- * @return Altered version of the upward-flowing parameters.
- */
- def mixI(pu: UI, node: InwardNode[DI, UI, BI]): UI = pu
-
- /** Function to generate and attach a monitor for this node input.
- *
- * @param bundle Inward bundle of this node to attach the monitor to.
- * @param edge Edge of this node used to parameterize the bundle.
- */
- def monitor(bundle: BI, edge: EI): Unit = {}
-
- /** Define how the edge should be rendered (e.g. in GraphML).
- *
- * @param e Edge to render.
- * @return [[RenderedEdge]] description of how the edge should be generated.
- */
- def render(e: EI): RenderedEdge
-}
-
-/** [[OutwardNodeImp]] defines the types that describe the outwards side of the [[BaseNode]].
- *
- * @tparam DO The type of the downward-flowing parameters generated by the outer side of the node
- * @tparam UO Tye type of the upward-flowing parameters received by the outer side of the node
- * @tparam EO The type of the diplomatically-resolved parameters for an Edge connected to the outer side of the node.
- * @tparam BO The type of the [[chisel3.Data]] (usually a [[chisel3.Bundle]]) used when connecting to the outer side of the node,
- * corresponding to the real hardware interface that is emitted along the graph edge,
- * generally parameterized by the [[EO]] type.
- */
-trait OutwardNodeImp[DO, UO, EO, BO <: Data]
-{
- /** Creates the outward edge parameters by combining the downward-flowing and upward-flowing parameters for edges
- * that connect to the outward side of this [[BaseNode]].
- *
- * It is left up to a user defining a particular protocol implementation to decide how the parameters flowing through
- * the graph in both directions on this Edge are combined into a single representation.
- *
- * @param pd The downward-flowing parameters going out of the node along the edge.
- * @param pu The upward-flowing parameters into the node along the edge.
- * @param p A view of [[Parameters]] at the point at which the returned edge is being bound.
- * @param sourceInfo [[SourceInfo]] of this edge.
- * @return An outward edge of this node.
- */
- def edgeO(pd: DO, pu: UO, p: Parameters, sourceInfo: SourceInfo): EO
-
- /** Create an outward Bundle parameterized by the outward edge.
- *
- * @param eo Outward Edge of this node.
- * @return An outward Bundle of this node parameterized by the negotiated Edge parameters.
- */
- def bundleO(eo: EO): BO
-
- /** Defines how outward parameters can be "mixed" or negotiated together.
- *
- * The default behavior is to just return `pd`.
- *
- * @param pd The downward-flowing parameters into the node along the edge.
- * @param node An outward node to "mix" the downward-flowing parameters into.
- * @return Altered version of the downward-flowing parameters.
- */
- def mixO(pd: DO, node: OutwardNode[DO, UO, BO]): DO = pd
-}
-
-/** The [[NodeImp]] combines an [[InwardNodeImp]] and an [[OutwardNodeImp]].
- *
- * This allows it to define whether it is a protocol-modifying (bridging) sort of node,
- * or whether it is an adapter type node that just modifies the parameters within a protocol.
- *
- * This class has no members and is solely used for holding type information.
- * Applications of diplomacy should extend [[NodeImp]] with a case object that sets concrete type arguments.
- *
- * @tparam D Type of the downward-flowing parameters of the node.
- * @tparam U Type of upward-flowing parameters of the node.
- * @tparam EO Type of the parameters describing an edge on the outer side of the node.
- * @tparam EI Type of the parameters describing an edge on the inner side of the node.
- * @tparam B Bundle type generated on edges connecting to this node.
- */
-abstract class NodeImp[D, U, EO, EI, B <: Data] extends Object
- with InwardNodeImp[D, U, EI, B]
- with OutwardNodeImp[D, U, EO, B]
-
-/** A [[NodeImp]] where the inward and outward edge parameters are of the same type.
- *
- * If, in a given protocol implementation, the parameters visible to the node on the inward side of an edge are
- * the same as the parameters visible to the node on the outward side of an edge,
- * [[SimpleNodeImp]] can be used instead of [[NodeImp]].
- *
- * @tparam D Type of the downward-flowing parameters of the node.
- * @tparam U Type of the upward-flowing parameters of the node.
- * @tparam E Edge Parameters describing the connections on either side of the node.
- * @tparam B Bundle type generated on edges connecting to this node.
- */
-abstract class SimpleNodeImp[D, U, E, B <: Data]
- extends NodeImp[D, U, E, E, B] {
- /** Creates the edge parameters by combining the downward-flowing and upward-flowing parameters for edges that connect to this node.
- *
- * It is left up to a user defining a particular protocol implementation to decide how the parameters flowing through the graph in
- * both directions are combined into a single representation on an Edge.
- *
- * @param pd The downward-flowing parameters into the node along the edge.
- * @param pu The upward-flowing parameters going out of the node along the edge.
- * @param p [[Parameters]]s which can be used during negotiation.
- * @param sourceInfo [[SourceInfo]] of this edge.
- * @return Negotiated edge parameters.
- */
- def edge(pd: D, pu: U, p: Parameters, sourceInfo: SourceInfo): E
-
- def edgeO(pd: D, pu: U, p: Parameters, sourceInfo: SourceInfo): E = edge(pd, pu, p, sourceInfo)
-
- def edgeI(pd: D, pu: U, p: Parameters, sourceInfo: SourceInfo): E = edge(pd, pu, p, sourceInfo)
-
- /** Generate the Bundle from the negotiated Edge parameters.
- *
- * @param e the negotiated Edge parameters
- * @return the corresponding Bundle of this node
- */
- def bundle(e: E): B
-
- def bundleO(e: E): B = bundle(e)
-
- def bundleI(e: E): B = bundle(e)
-}
-
-/** [[BaseNode]] is the abstract base class of the type hierarchy of diplomacy node classes.
- *
- * @param valName [[ValName]] of this node, used by naming inference.
- */
-abstract class BaseNode(implicit val valName: ValName) {
- /** All subclasses of [[BaseNode]]s are expected to be instantiated only within [[LazyModule]]s.
- *
- * Sometimes one wants to view the entire diplomacy graph in a way
- * where you do not care about the specific types of the edges.
- * [[BaseNode]]s are type-erased and provide this view.
- *
- * @return The [[LazyModule]] which contains this Node.
- */
- val scope: Option[LazyModule] = LazyModule.scope
-
- /** @return The index for this node in the containing [[LazyModule]]/[[LazyScope]]'s list of [[BaseNode]]s */
- val index: Int = scope.map(_.nodes.size).getOrElse(0)
-
- /** @return The [[LazyModule]] which contains this [[BaseNode]] */
- def lazyModule: LazyModule = scope.get
-
- // Prepend this node to the current [[LazyModule]]'s list of nodes
- scope.foreach { lm => lm.nodes = this :: lm.nodes }
-
- /** @return The serial number for this node in the global list of [[BaseNode]]s. */
- val serial: Int = BaseNode.serial
-
- BaseNode.serial = BaseNode.serial + 1
-
- /** Instantiate this node.
- *
- * This happens after all nodes connections have been made and we are ready to perform parameter negotiation.
- * This also determines which connections need to leave this node's LazyScope and cross hierarchical boundaries.
- * That information is captured in [[Dangle]]s which are returned from this function.
- *
- * @return A sequence of [[Dangle]]s from this node that leave this [[BaseNode]]'s [[LazyScope]].
- */
- protected[diplomacy] def instantiate(): Seq[Dangle]
- /** Determine the [[Dangle]]'s for connections without instantiating the node, or any child nodes
- *
- * @return A sequence of [[Dangle]]s from this node that leave this [[BaseNode]]'s [[LazyScope]].
- */
- protected[diplomacy] def cloneDangles(): Seq[Dangle]
-
- /** @return name of this node. */
- def name: String = scope.map(_.name).getOrElse("TOP") + "." + valName.name
-
- /** Determines whether or not this node will be excluded from the graph visualization.
- *
- * By default, if this node has neither inputs nor outputs it will be excluded.
- */
- def omitGraphML: Boolean = outputs.isEmpty && inputs.isEmpty
-
- /** Debug string of this node, used in [[LazyModule.graphML]]. */
- lazy val nodedebugstring: String = ""
-
- /** Mark whether this node represents a circuit "identity" that outputs its inputs unchanged.
- *
- * This information may be used to elide monitors or inline the parent module.
- */
- def circuitIdentity: Boolean = false
-
- /** @return A sequence of [[LazyModule]] up to and including Top. */
- def parents: Seq[LazyModule] = scope.map(lm => lm +: lm.parents).getOrElse(Nil)
-
- /** @return The context string for debug. */
- def context: String = {
- s"""$description $name node:
- |parents: ${parents.map(_.name).mkString("/")}
- |locator: ${scope.map(_.line).getOrElse("")}
- |""".stripMargin
- }
-
- /** Determines the name to be used in elements of auto-punched bundles.
- *
- * It takes the name of the node as determined from [[valName]],
- * converts camel case into snake case, and strips "Node" or "NodeOpt" suffixes.
- */
- def wirePrefix: String = {
- val camelCase = "([a-z])([A-Z])".r
- val decamel = camelCase.replaceAllIn(valName.name, _ match { case camelCase(l, h) => l + "_" + h })
- val name = decamel.toLowerCase.stripSuffix("_opt").stripSuffix("node").stripSuffix("_")
- if (name.isEmpty) "" else name + "_"
- }
-
- /** @return [[BaseNode]] description, which should be defined by subclasses and is generally expected to be a constant. */
- def description: String
-
- /** @return [[BaseNode]] instance description, which can be overridden with more detailed information about each node. */
- def formatNode: String = ""
-
- /** @return Metadata to visualize inward edges into this node. */
- def inputs: Seq[(BaseNode, RenderedEdge)]
-
- /** @return Metadata to visualize outward edges from this node. */
- def outputs: Seq[(BaseNode, RenderedEdge)]
-
- /** @return Whether this node can handle [[BIND_FLEX]] type connections on either side.
- *
- * For example, a node `b` will have [[flexibleArityDirection]] be `true` if both are legal:
- * `a :*=* b :*= c`, which resolves to `a :*= b :*= c`
- * or
- * `a :=* b :*=* c`, which resolves to `a :=* b :=* c`
- *
- * If this is `false`, the node can only support `:*=*` if it connects to a node with `flexibleArityDirection = true`
- */
- protected[diplomacy] def flexibleArityDirection: Boolean = false
-
- /** @return The sink cardinality.
- *
- * How many times is this node used as a sink.
- */
- protected[diplomacy] val sinkCard: Int
-
- /** @return The source cardinality.
- *
- * How many times is this node used as a source.
- */
- protected[diplomacy] val sourceCard: Int
-
- /** @return The "flex" cardinality.
- *
- * How many times is this node used in a way that could be either source or sink, depending on final
- * directional determination.
- */
- protected[diplomacy] val flexes: Seq[BaseNode]
-
- /** Resolves the flex to be either source or sink.
- *
- * @return A value >= 0 if it is sink cardinality, a negative value for source cardinality. The magnitude of the value does not matter.
- */
- protected[diplomacy] val flexOffset: Int
-}
-
-/** Companion object for [[BaseNode]], which is only used to hold the the global serial number of all [[BaseNode]]s. */
-object BaseNode {
- protected[diplomacy] var serial = 0
-}
-
-/** Trait that enables a string representation of an edge. */
-trait FormatEdge {
- def formatEdge: String
-}
-
-/** Trait that enables iterating over a [[BaseNode]]'s edges to produce a formatted string representation.
- *
- * In practice this is generally GraphML metadata.
- */
-trait FormatNode[I <: FormatEdge, O <: FormatEdge] extends BaseNode {
- def edges: Edges[I,O]
-
- /** Format the edges of the [[BaseNode]] for emission (generally in GraphML). */
- override def formatNode = if (circuitIdentity) "" else {
- edges.out.map(currEdge =>
- "On Output Edge:\n\n" + currEdge.formatEdge).mkString +
- "\n---------------------------------------------\n\n" +
- edges.in.map(currEdge =>
- "On Input Edge:\n\n" + currEdge.formatEdge).mkString
- }
-}
-
-/** A Handle with no explicitly defined binding functionality.
- *
- * A [[NoHandle]] is at the top of the Handle type hierarchy, but it does not define any binding operators,
- * so by itself a [[NoHandle]] cannot be used on either side of a bind operator.
- *
- * For example, a source node connected directly to a sink node produces a [[NoHandle]],
- * because there are no further bindings that could be applied to either side of the pair of nodes.
- *
- * The other Handle types extend this type and bestow actual binding semantics.
- * They can always be used wherever a [[NoHandle]] is expected because a [[NoHandle]]
- * doesn't provide any guaranteed behavior.
- *
- * Handle algebra:
- *
- * "x---x" [[NoHandle]]
- * "x---<" [[InwardNodeHandle]]
- * "<---x" [[OutwardNodeHandle]]
- * "<---<" (Full) [[NodeHandle]]
- *
- * "<" can be bound to (arrow points in the direction of binding).
- * "x" cannot be bound to.
- *
- * The left side is outer, the right side is inner.
- *
- * Two Handles can be bound if their adjacent ends are both "<".
- */
-trait NoHandle
-case object NoHandleObject extends NoHandle
-
-/** A Handle that can be used on either side of a bind operator. */
-trait NodeHandle[DI, UI, EI, BI <: Data, DO, UO, EO, BO <: Data]
- extends InwardNodeHandle[DI, UI, EI, BI] with OutwardNodeHandle[DO, UO, EO, BO] {
- /** Connects two full nodes handles => full node handle.
- *
- * <---< := <---< == <---<
- * This and that node are both [[BIND_ONCE]].
- *
- * @param h A source node also with sink handle.
- * @return A [[NodeHandle]] with that node as `inwardNode`, this node as `outwardNode`.
- */
- 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) }
-
- /** Connects two full nodes handles => full node handle.
- *
- * <---< :*= <---< == <---<
- * [[BIND_STAR]] this node as sink, [[BIND_QUERY]] that node as source.
- *
- * @param h A source node also with sink handle.
- * @return A [[NodeHandle]] with that node as `InwardNode`, this node as `OutwardNode`.
- */
- 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) }
-
- /** Connects two full nodes handles => full node handle.
- *
- * <---< :=* <---< == <---<
- * [[BIND_QUERY]] this node as sink, [[BIND_STAR]] that node as source.
- *
- * @param h A source node also with sink handle.
- * @return A [[NodeHandle]] with that node as `InwardNode`, this node as `OutwardNode`.
- */
- 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) }
-
- /** Connects two full nodes handles => full node handle.
- *
- * <---< :*=* <---< == <---<
- * [[BIND_FLEX]] this node as sink, [[BIND_FLEX]] that node as source.
- *
- * @param h A source node also with sink handle.
- * @return A [[NodeHandle]] with that node as `inwardNode`, this node as `outwardNode`.
- */
- 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) }
-
- /** Connects a full node with an output node => an output handle.
- *
- * <---< := <---x == <---x
- * [[BIND_ONCE]] this node as sink, [[BIND_ONCE]] that node as source.
- *
- * @param h A source node also without sink handle.
- * @return A [[OutwardNodeHandle]] with this node as `outwardNode`.
- */
- override def := [EY](h: OutwardNodeHandle[DI, UI, EY, BI])(implicit p: Parameters, sourceInfo: SourceInfo): OutwardNodeHandle[DO, UO, EO, BO] = { bind(h, BIND_ONCE); this }
-
- /** Connects a full node with an output node => an output handle.
- *
- * <---< :*= <---x == <---x
- * [[BIND_STAR]] this node as sink, [[BIND_QUERY]] that node as source.
- *
- * @param h A source node also without sink handle.
- * @return A [[OutwardNodeHandle]] with this node as `outwardNode`.
- */
- override def :*= [EY](h: OutwardNodeHandle[DI, UI, EY, BI])(implicit p: Parameters, sourceInfo: SourceInfo): OutwardNodeHandle[DO, UO, EO, BO] = { bind(h, BIND_STAR); this }
-
- /** Connects a full node with an output => an output.
- *
- * <---< :=* <---x == <---x
- * [[BIND_QUERY]] this node as sink, [[BIND_STAR]] that node as source.
- *
- * @param h A source node also without sink handle.
- * @return A [[OutwardNodeHandle]] with this node as `outwardNode`.
- */
- override def :=* [EY](h: OutwardNodeHandle[DI, UI, EY, BI])(implicit p: Parameters, sourceInfo: SourceInfo): OutwardNodeHandle[DO, UO, EO, BO] = { bind(h, BIND_QUERY); this }
-
- /** Connects a full node with an output => an output.
- *
- * <---< :*=* <---x == <---x
- * [[BIND_FLEX]] this node as sink, [[BIND_FLEX]] that node as source.
- *
- * @param h A source node also without sink handle.
- * @return A [[OutwardNodeHandle]] with this node as `outwardNode`.
- */
- 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 {
- /** generate a [[NodeHandle]] by combining an [[InwardNodeHandle]] and an [[OutwardNodeHandle]].
- *
- * @param i Inward node handle.
- * @param o Outward node handle.
- * @return [[NodeHandlePair]] with `inwardNode` of `i`, `outwardNode` of `o`.
- */
- def apply[DI, UI, EI, BI <: Data, DO, UO, EO, BO <: Data](i: InwardNodeHandle[DI, UI, EI, BI], o: OutwardNodeHandle[DO, UO, EO, BO]) = new NodeHandlePair(i, o)
-}
-
-/** A data structure that preserves information about the innermost and outermost Nodes in a [[NodeHandle]]. */
-class NodeHandlePair[DI, UI, EI, BI <: Data, DO, UO, EO, BO <: Data]
- (inwardHandle: InwardNodeHandle[DI, UI, EI, BI], outwardHandle: OutwardNodeHandle[DO, UO, EO, BO])
- extends NodeHandle[DI, UI, EI, BI, DO, UO, EO, BO] {
- /** @return [[InwardNode]] of [[inwardHandle]]. */
- val inward: InwardNode[DI, UI, BI] = inwardHandle.inward
-
- /** @return [[OutwardNode]] of [[outwardHandle]]. */
- val outward: OutwardNode[DO, UO, BO] = outwardHandle.outward
-
- /** @return The innermost [[InwardNodeImp]] of this [[NodeHandlePair]]. */
- def inner: InwardNodeImp[DI, UI, EI, BI] = inwardHandle.inner
-
- /** @return The outermost [[OutwardNodeImp]] of [[NodeHandlePair]]. */
- def outer: OutwardNodeImp[DO, UO, EO, BO] = outwardHandle.outer
-}
-
-/** A handle for an [[InwardNode]], which may appear on the left side of a bind operator. */
-trait InwardNodeHandle[DI, UI, EI, BI <: Data] extends NoHandle
-{
- /** @return [[InwardNode]] of `inwardHandle`. */
- def inward: InwardNode[DI, UI, BI]
-
- /** @return [[InwardNodeImp]] of `inwardHandle`. */
- def inner: InwardNodeImp[DI, UI, EI, BI]
-
- /** Bind this node to an [[OutwardNodeHandle]]. */
- protected def bind[EY](h: OutwardNodeHandle[DI, UI, EY, BI], binding: NodeBinding)(implicit p: Parameters, sourceInfo: SourceInfo): Unit = inward.bind(h.outward, binding)
-
- /** Connect an input node with a full node => inward node handle.
- *
- * x---< := <---< == x---<
- * [[BIND_ONCE]] this node as sink, [[BIND_ONCE]] that node as source.
- *
- * @param h A source node also with sink handle.
- * @return A [[NodeHandle]] with that node as `inwardNode`, this node as `outwardNode`.
- */
- 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 }
-
- /** Connect an input node with a full node => an input node.
- *
- * x---< :*= <---< == x---<
- * [[BIND_STAR]] this node as sink, [[BIND_QUERY]] that node as source.
- *
- * @param h A Source node also with sink handle.
- * @return A [[NodeHandle]] with that node as `inwardNode`, this node as `outwardNode`.
- */
- 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 }
-
- /** Connect an input node with a full node => an inward node handle.
- *
- * x---< :=* <---< == x---<
- * [[BIND_QUERY]] this node as sink, [[BIND_STAR]] that node as source.
- *
- * @param h A source node also with sink handle.
- * @return A [[NodeHandle]] with that node as `inwardNode`, this node as `outwardNode`.
- */
- 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 }
-
- /** Connect an input node with a full node => an input node.
- *
- * x---< :*=* <---< == x---<
- * [[BIND_FLEX]] this node as sink, [[BIND_FLEX]] that node as source.
- *
- * @param h A source node also with sink handle.
- * @return A [[NodeHandle]] with that node as `inwardNode`, this node as `outwardNode`.
- */
- 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 }
-
- /** Connect an input node with output node => no node.
- *
- * x---< := <---x == x---x
- * [[BIND_ONCE]] this node as sink, [[BIND_ONCE]] that node as source.
- *
- * @param h A source node also without sink handle.
- * @return A [[NoHandle]] since neither side can bind to a node.
- */
- def := [EY](h: OutwardNodeHandle[DI, UI, EY, BI])(implicit p: Parameters, sourceInfo: SourceInfo): NoHandle = { bind(h, BIND_ONCE); NoHandleObject }
-
- /** Connect an input node with output node => no node.
- *
- * x---< :*= <---x == x---x
- * [[BIND_STAR]] this node as sink, [[BIND_QUERY]] that node as source.
- *
- * @param h A source node also without sink handle.
- * @return A [[NoHandle]] since neither side can bind to a node.
- */
- def :*= [EY](h: OutwardNodeHandle[DI, UI, EY, BI])(implicit p: Parameters, sourceInfo: SourceInfo): NoHandle = { bind(h, BIND_STAR); NoHandleObject }
-
- /** Connect an input node with output node => no node.
- *
- * x---< :=* <---x == x---x
- * [[BIND_QUERY]] this node as sink, [[BIND_STAR]] that node as source.
- *
- * @param h A source node also without sink handle.
- * @return A [[NoHandle]] since neither side can bind to another node.
- */
- def :=* [EY](h: OutwardNodeHandle[DI, UI, EY, BI])(implicit p: Parameters, sourceInfo: SourceInfo): NoHandle = { bind(h, BIND_QUERY); NoHandleObject }
-
- /** Connect an input node with output node => no node.
- *
- * x---< :*=* <---x == x---x
- * [[BIND_FLEX]] this node as sink, [[BIND_FLEX]] that node as source.
- *
- * @param h A source node also without sink handle.
- * @return A [[NoHandle]] since neither side can bind to another node.
- */
- def :*=*[EY](h: OutwardNodeHandle[DI, UI, EY, BI])(implicit p: Parameters, sourceInfo: SourceInfo): NoHandle = { bind(h, BIND_FLEX); NoHandleObject }
-}
-
-/** Enumeration of types of binding operations. */
-sealed trait NodeBinding
-
-/** Only connects a single edge. */
-case object BIND_ONCE extends NodeBinding {
- override def toString: String = "once"
-}
-
-/** Connects N (N >= 0) edges.
- *
- * The other side of the edge determines cardinality.
- */
-case object BIND_QUERY extends NodeBinding {
- override def toString: String = "query"
-}
-
-/** Connect N (N >= 0) edges.
- *
- * Our side of the edge determines cardinality.
- */
-case object BIND_STAR extends NodeBinding {
- override def toString: String = "star"
-}
-
-/** Connect N (N >= 0) connections.
- *
- * The number of edges N will be determined by either the right or left side,
- * once the direction ([[BIND_STAR]] or [[BIND_QUERY]]) is determined by the other connections as well.
- */
-case object BIND_FLEX extends NodeBinding {
- override def toString: String = "flex"
-}
-
-/** A Node that defines inward behavior, meaning that it can have edges coming into it and be used on the left side of binding expressions. */
-trait InwardNode[DI, UI, BI <: Data] extends BaseNode {
- /** accumulates input connections. */
- private val accPI = ListBuffer[(Int, OutwardNode[DI, UI, BI], NodeBinding, Parameters, SourceInfo)]()
-
- /** Initially `false`, set to `true` once [[iBindings]] has been evaluated. */
- private var iRealized = false
-
- /** @return debug information of [[iBindings]]. */
- def iBindingInfo: String = s"""${iBindings.size} inward nodes bound: [${iBindings.map(n => s"${n._3}-${n._2.name}").mkString(",")}]"""
-
-
- /** The accumulated number of input connections. */
- protected[diplomacy] def iPushed: Int = accPI.size
-
- /** Accumulate an input connection.
- *
- * Can only be called before [[iBindings]] is accessed.
- *
- * @param index index of this [[InwardNode]] in that [[OutwardNode]].
- * @param node the [[OutwardNode]] to bind to this [[InwardNode]].
- * @param binding [[NodeBinding]] type.
- */
- protected[diplomacy] def iPush(index: Int, node: OutwardNode[DI, UI, BI], binding: NodeBinding)(implicit p: Parameters, sourceInfo: SourceInfo): Unit = {
- val info = sourceLine(sourceInfo, " at ", "")
- require (!iRealized,
- s"""Diplomacy has detected a problem in your code:
- |The following node was incorrectly connected as a sink to ${node.name} after its .module was evaluated at $info.
- |$context
- |$iBindingInfo
- |""".stripMargin)
- accPI += ((index, node, binding, p, sourceInfo))
- }
-
- /** Ends the binding accumulation stage and returns all the input bindings to this node.
- *
- * Evaluating this lazy val will mark the inwards bindings as frozen,
- * preventing subsequent bindings from being created via [[iPush]].
- *
- * The bindings are each a tuple of:
- * - numeric index of this binding in the other end of [[OutwardNode]].
- * - [[OutwardNode]] on the other end of this binding.
- * - [[NodeBinding]] describing the type of binding.
- * - A view of [[Parameters]] where the binding occurred.
- * - [[SourceInfo]] for source-level error reporting.
- */
- protected[diplomacy] lazy val iBindings: immutable.Seq[(Int, OutwardNode[DI, UI, BI], NodeBinding, Parameters, SourceInfo)] = { iRealized = true; accPI.result() }
-
- /** resolved [[BIND_STAR]] binding of inward nodes: how many connections the star represents. */
- protected[diplomacy] val iStar: Int
-
- /** A mapping to convert Node binding index to port range.
- *
- * @return a sequence of tuple of mapping, the item in each a tuple of:
- * - index: the index of connected [[OutwardNode]]
- * - element: port range of connected [[OutwardNode]]
- */
- protected[diplomacy] val iPortMapping: Seq[(Int, Int)]
-
- /** "Forward" an input connection through this node so that the node can be removed from the graph.
- *
- * @return None if no forwarding is needing.
- */
- protected[diplomacy] def iForward(x: Int): Option[(Int, InwardNode[DI, UI, BI])] = None
-
- /** Downward-flowing inward parameters.
- *
- * Generated from the nodes connected to the inward side of this node and sent downstream to this node.
- */
- protected[diplomacy] val diParams: Seq[DI]
-
- /** Upward-flowing inward parameters.
- *
- * Generated by this node and sent upstream to the nodes connected to the inward side of this node.
- */
- protected[diplomacy] val uiParams: Seq[UI]
-
- /** Create a binding from this node to an [[OutwardNode]].
- *
- * @param h The [[OutwardNode]] to bind to.
- * @param binding [[NodeBinding]] the type of binding.
- */
- protected[diplomacy] def bind(h: OutwardNode[DI, UI, BI], binding: NodeBinding)(implicit p: Parameters, sourceInfo: SourceInfo): Unit
-}
-
-/** A Handle for OutwardNodes, which may appear on the right side of a bind operator. */
-trait OutwardNodeHandle[DO, UO, EO, BO <: Data] extends NoHandle {
- /** @return [[OutwardNode]] of `outwardHandle`. */
- def outward: OutwardNode[DO, UO, BO]
-
- /** @return [[OutwardNodeImp]] of `inwardHandle`. */
- def outer: OutwardNodeImp[DO, UO, EO, BO]
-}
-
-/** A Node that defines outward behavior, meaning that it can have edges coming out of it. */
-trait OutwardNode[DO, UO, BO <: Data] extends BaseNode {
- /** Accumulates output connections. */
- private val accPO = ListBuffer[(Int, InwardNode [DO, UO, BO], NodeBinding, Parameters, SourceInfo)]()
-
- /** Initially set to `true`, this is set to false once [[oBindings]] is referenced. */
- private var oRealized = false
-
- /** @return debug information of [[oBindings]]. */
- def oBindingInfo: String = s"""${oBindings.size} outward nodes bound: [${oBindings.map(n => s"${n._3}-${n._2.name}").mkString(",")}]"""
-
- /** The accumulated number of output connections of this node. */
- protected[diplomacy] def oPushed: Int = accPO.size
-
- /** Accumulate an output connection.
- *
- * Can only be called before [[oBindings]] is accessed.
- *
- * @param index Index of this [[OutwardNode]] in that [[InwardNode]].
- * @param node [[InwardNode]] to bind to.
- * @param binding Binding type.
- */
- protected[diplomacy] def oPush(index: Int, node: InwardNode [DO, UO, BO], binding: NodeBinding)(implicit p: Parameters, sourceInfo: SourceInfo): Unit = {
- val info = sourceLine(sourceInfo, " at ", "")
- require (!oRealized,
- s"""Diplomacy has detected a problem in your code:
- |The following node was incorrectly connected as a source to ${node.name} after its .module was evaluated at $info.
- |$context
- |$oBindingInfo
- |""".stripMargin)
- accPO += ((index, node, binding, p, sourceInfo))
- }
-
- /** Ends the binding accumulation stage and returns all the output bindings to this node.
- *
- * Evaluating this lazy val will mark the outward bindings as frozen,
- * preventing subsequent bindings from being created via [[oPush]].
- *
- * The bindings are each a tuple of:
- * - numeric index of this binding in the other end of [[InwardNode]].
- * - [[InwardNode]] on the other end of this binding
- * - [[NodeBinding]] describing the type of binding
- * - A view of [[Parameters]] where the binding occurred.
- * - [[SourceInfo]] for source-level error reporting
- */
- protected[diplomacy] lazy val oBindings: Seq[(Int, InwardNode[DO, UO, BO], NodeBinding, Parameters, SourceInfo)] = { oRealized = true; accPO.result() }
-
- /** resolved [[BIND_STAR]] binding of outward nodes: how many connections the star represents. */
- protected[diplomacy] val oStar: Int
-
- /** A mapping to convert Node binding index to port range.
- *
- * @return a sequence of tuple of mapping, the item in each a tuple of:
- * - index: the index of connected [[InwardNode]]
- * - element: port range of connected [[InwardNode]]
- */
- protected[diplomacy] val oPortMapping: Seq[(Int, Int)]
-
- /** "Forward" an output connection through this node so that the node can be removed from the graph.
- *
- * @return None if no forwarding is needed.
- */
- protected[diplomacy] def oForward(x: Int): Option[(Int, OutwardNode[DO, UO, BO])] = None
-
- /** Upward-flowing outward parameters.
- *
- * Generated from the nodes connected to the outward side of this node and sent upstream to this node.
- */
- protected[diplomacy] val uoParams: Seq[UO]
-
- /** Downward-flowing outward parameters.
- *
- * Generated by this node and sent downstream to the nodes connected to the outward side of this node.
- */
- protected[diplomacy] val doParams: Seq[DO]
-}
-
-abstract class CycleException(kind: String, loop: Seq[String]) extends Exception(s"Diplomatic $kind cycle detected involving $loop")
-case class StarCycleException(loop: Seq[String] = Nil) extends CycleException("star", loop)
-case class DownwardCycleException(loop: Seq[String] = Nil) extends CycleException("downward", loop)
-case class UpwardCycleException(loop: Seq[String] = Nil) extends CycleException("upward", loop)
-
-/** [[Edges]] is a collection of parameters describing the functionality and connection for an interface,
- * which is often derived from the interconnection protocol and can inform the parameterization
- * of the hardware bundles that actually implement the protocol.
- */
-case class Edges[EI, EO](in: Seq[EI], out: Seq[EO])
-
-/** The sealed node class in the package, all node are derived from it.
- *
- * @param inner Sink interface implementation.
- * @param outer Source interface implementation.
- * @param valName val name of this node.
- * @tparam DI Downward-flowing parameters received on the inner side of the node.
- * It is usually a brunch of parameters describing the protocol parameters from a source.
- * For an [[InwardNode]], it is determined by the connected [[OutwardNode]].
- * Since it can be connected to multiple sources, this parameter is always a Seq of source port parameters.
- * @tparam UI Upward-flowing parameters generated by the inner side of the node.
- * It is usually a brunch of parameters describing the protocol parameters of a sink.
- * For an [[InwardNode]], it is determined itself.
- * @tparam EI Edge Parameters describing a connection on the inner side of the node.
- * It is usually a brunch of transfers specified for a sink according to protocol.
- * @tparam BI Bundle type used when connecting to the inner side of the node.
- * It is a hardware interface of this sink interface.
- * It should extends from [[chisel3.Data]], which represents the real hardware.
- * @tparam DO Downward-flowing parameters generated on the outer side of the node.
- * It is usually a brunch of parameters describing the protocol parameters of a source.
- * For an [[OutwardNode]], it is determined itself.
- * @tparam UO Upward-flowing parameters received by the outer side of the node.
- * It is usually a brunch of parameters describing the protocol parameters from a sink.
- * For an [[OutwardNode]], it is determined by the connected [[InwardNode]].
- * Since it can be connected to multiple sinks, this parameter is always a Seq of sink port parameters.
- * @tparam EO Edge Parameters describing a connection on the outer side of the node.
- * It is usually a brunch of transfers specified for a source according to protocol.
- * @tparam BO Bundle type used when connecting to the outer side of the node.
- * It is a hardware interface of this source interface.
- * It should extends from [[chisel3.Data]], which represents the real hardware.
- *
- * @note Call Graph of [[MixedNode]]
- * - line `─`: source is process by a function and generate pass to others
- * - Arrow `→`: target of arrow is generated by source
- *
- * {{{
- * (from the other node)
- * ┌─────────────────────────────────────────────────────────[[InwardNode.uiParams]]─────────────┐
- * ↓ │
- * (binding node when elaboration) [[OutwardNode.uoParams]]────────────────────────[[MixedNode.mapParamsU]]→──────────┐ │
- * [[InwardNode.accPI]] │ │ │
- * │ │ (based on protocol) │
- * │ │ [[MixedNode.inner.edgeI]] │
- * │ │ ↓ │
- * ↓ │ │ │
- * (immobilize after elaboration) (inward port from [[OutwardNode]]) │ ↓ │
- * [[InwardNode.iBindings]]──┐ [[MixedNode.iDirectPorts]]────────────────────→[[MixedNode.iPorts]] [[InwardNode.uiParams]] │
- * │ │ ↑ │ │ │
- * │ │ │ [[OutwardNode.doParams]] │ │
- * │ │ │ (from the other node) │ │
- * │ │ │ │ │ │
- * │ │ │ │ │ │
- * │ │ │ └────────┬──────────────┤ │
- * │ │ │ │ │ │
- * │ │ │ │ (based on protocol) │
- * │ │ │ │ [[MixedNode.inner.edgeI]] │
- * │ │ │ │ │ │
- * │ │ (from the other node) │ ↓ │
- * │ └───[[OutwardNode.oPortMapping]] [[OutwardNode.oStar]] │ [[MixedNode.edgesIn]]───┐ │
- * │ ↑ ↑ │ │ ↓ │
- * │ │ │ │ │ [[MixedNode.in]] │
- * │ │ │ │ ↓ ↑ │
- * │ (solve star connection) │ │ │ [[MixedNode.bundleIn]]──┘ │
- * ├───[[MixedNode.resolveStar]]→─┼─────────────────────────────┤ └────────────────────────────────────┐ │
- * │ │ │ [[MixedNode.bundleOut]]─┐ │ │
- * │ │ │ ↑ ↓ │ │
- * │ │ │ │ [[MixedNode.out]] │ │
- * │ ↓ ↓ │ ↑ │ │
- * │ ┌─────[[InwardNode.iPortMapping]] [[InwardNode.iStar]] [[MixedNode.edgesOut]]──┘ │ │
- * │ │ (from the other node) ↑ │ │
- * │ │ │ │ │ │
- * │ │ │ [[MixedNode.outer.edgeO]] │ │
- * │ │ │ (based on protocol) │ │
- * │ │ │ │ │ │
- * │ │ │ ┌────────────────────────────────────────┤ │ │
- * │ │ │ │ │ │ │
- * │ │ │ │ │ │ │
- * │ │ │ │ │ │ │
- * (immobilize after elaboration)│ ↓ │ │ │ │
- * [[OutwardNode.oBindings]]─┘ [[MixedNode.oDirectPorts]]───→[[MixedNode.oPorts]] [[OutwardNode.doParams]] │ │
- * ↑ (inward port from [[OutwardNode]]) │ │ │ │
- * │ ┌─────────────────────────────────────────┤ │ │ │
- * │ │ │ │ │ │
- * │ │ │ │ │ │
- * [[OutwardNode.accPO]] │ ↓ │ │ │
- * (binding node when elaboration) │ [[InwardNode.diParams]]─────→[[MixedNode.mapParamsD]]────────────────────────────┘ │ │
- * │ ↑ │ │
- * │ └──────────────────────────────────────────────────────────────────────────────────────────┘ │
- * └──────────────────────────────────────────────────────────────────────────────────────────────────────────┘
- * }}}
- */
-sealed abstract class MixedNode[DI, UI, EI, BI <: Data, DO, UO, EO, BO <: Data](
- val inner: InwardNodeImp [DI, UI, EI, BI],
- val outer: OutwardNodeImp[DO, UO, EO, BO])(
- implicit valName: ValName)
- extends BaseNode with NodeHandle[DI, UI, EI, BI, DO, UO, EO, BO] with InwardNode[DI, UI, BI] with OutwardNode[DO, UO, BO] {
- // Generate a [[NodeHandle]] with inward and outward node are both this node.
- val inward = this
- val outward = this
-
- /** Debug info of nodes binding. */
- def bindingInfo: String =
- s"""$iBindingInfo
- |$oBindingInfo
- |""".stripMargin
-
- /** Debug info of ports connecting. */
- def connectedPortsInfo: String =
- s"""${oPorts.size} outward ports connected: [${oPorts.map(_._2.name).mkString(",")}]
- |${iPorts.size} inward ports connected: [${iPorts.map(_._2.name).mkString(",")}]
- |""".stripMargin
-
- /** Debug info of parameters propagations. */
- def parametersInfo: String =
- s"""${doParams.size} downstream outward parameters: [${doParams.mkString(",")}]
- |${uoParams.size} upstream outward parameters: [${uoParams.mkString(",")}]
- |${diParams.size} downstream inward parameters: [${diParams.mkString(",")}]
- |${uiParams.size} upstream inward parameters: [${uiParams.mkString(",")}]
- |""".stripMargin
-
- /** For a given node, converts [[OutwardNode.accPO]] and [[InwardNode.accPI]] to [[MixedNode.oPortMapping]] and [[MixedNode.iPortMapping]].
- *
- * Given counts of known inward and outward binding and inward and outward star bindings, return the resolved inward stars and outward stars.
- *
- * This method will also validate the arguments and throw a runtime error if the values are unsuitable for this type of node.
- *
- * @param iKnown Number of known-size ([[BIND_ONCE]]) input bindings.
- * @param oKnown Number of known-size ([[BIND_ONCE]]) output bindings.
- * @param iStar Number of unknown size ([[BIND_STAR]]) input bindings.
- * @param oStar Number of unknown size ([[BIND_STAR]]) output bindings.
- * @return A Tuple of the resolved number of input and output connections.
- */
- protected[diplomacy] def resolveStar(iKnown: Int, oKnown: Int, iStar: Int, oStar: Int): (Int, Int)
-
- /** Function to generate downward-flowing outward params from the downward-flowing input params and the current output ports.
- *
- * @param n The size of the output sequence to generate.
- * @param p Sequence of downward-flowing input parameters of this node.
- * @return A `n`-sized sequence of downward-flowing output edge parameters.
- */
- protected[diplomacy] def mapParamsD(n: Int, p: Seq[DI]): Seq[DO]
-
- /** Function to generate upward-flowing input parameters from the upward-flowing output parameters [[uiParams]].
- *
- * @param n Size of the output sequence.
- * @param p Upward-flowing output edge parameters.
- * @return A n-sized sequence of upward-flowing input edge parameters.
- */
- protected[diplomacy] def mapParamsU(n: Int, p: Seq[UO]): Seq[UI]
-
- /** @return The sink cardinality of the node, the number of outputs bound with [[BIND_QUERY]] summed with inputs bound with [[BIND_STAR]]. */
- protected[diplomacy] lazy val sinkCard: Int = oBindings.count(_._3 == BIND_QUERY) + iBindings.count(_._3 == BIND_STAR)
-
- /** @return The source cardinality of this node, the number of inputs bound with [[BIND_QUERY]] summed with the number of output bindings bound with [[BIND_STAR]]. */
- protected[diplomacy] lazy val sourceCard: Int = iBindings.count(_._3 == BIND_QUERY) + oBindings.count(_._3 == BIND_STAR)
-
- /** @return list of nodes involved in flex bindings with this node. */
- protected[diplomacy] lazy val flexes: Seq[BaseNode] = oBindings.filter(_._3 == BIND_FLEX).map(_._2) ++ iBindings.filter(_._3 == BIND_FLEX).map(_._2)
-
- /** Resolves the flex to be either source or sink and returns the offset where the [[BIND_STAR]] operators begin greedily taking up the remaining connections.
- *
- * @return A value >= 0 if it is sink cardinality, a negative value for source cardinality. The magnitude of the return value is not relevant.
- */
- protected[diplomacy] lazy val flexOffset: Int = {
- /** Recursively performs a depth-first search of the [[flexes]],
- * [[BaseNode]]s connected to this node with flex operators.
- * The algorithm bottoms out when we either get to a node we have already visited
- * or when we get to a connection that is not a flex and can set the direction for us.
- * Otherwise, recurse by visiting the `flexes` of each node in the current set
- * and decide whether they should be added to the set or not.
- *
- * @return the mapping of [[BaseNode]] indexed by their serial numbers.
- */
- def DFS(v: BaseNode, visited: Map[Int, BaseNode]): Map[Int, BaseNode] = {
- if (visited.contains(v.serial) || !v.flexibleArityDirection) {
- visited
- } else {
- v.flexes.foldLeft(visited + (v.serial -> v))((sum, n) => DFS(n, sum))
- }
- }
-
- /** Determine which [[BaseNode]] are involved in resolving the flex connections to/from this node.
- *
- * @example
- * {{{
- * a :*=* b :*=* c
- * d :*=* b
- * e :*=* f
- * }}}
- *
- * `flexSet` for `a`, `b`, `c`, or `d` will be `Set(a, b, c, d)`
- * `flexSet` for `e` or `f` will be `Set(e,f)`
- */
- val flexSet = DFS(this, Map()).values
-
- /** The total number of :*= operators where we're on the left. */
- val allSink = flexSet.map(_.sinkCard).sum
-
- /** The total number of :=* operators used when we're on the right. */
- val allSource = flexSet.map(_.sourceCard).sum
-
- require (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
- }
-
- /** @return A value >= 0 if it is sink cardinality, a negative value for source cardinality. */
- protected[diplomacy] def edgeArityDirection(n: BaseNode): Int = {
- if ( flexibleArityDirection) flexOffset else
- if (n.flexibleArityDirection) n.flexOffset else
- 0
- }
-
- /** For a node which is connected between two nodes, select the one that will influence the direction of the flex resolution. */
- protected[diplomacy] def edgeAritySelect(n: BaseNode, l: => Int, r: => Int): Int = {
- val dir = edgeArityDirection(n)
- if (dir < 0) l else if (dir > 0) r else 1
- }
-
- /** Ensure that the same node is not visited twice in resolving `:*=`, etc operators. */
- private var starCycleGuard = false
-
- /** Resolve all the star operators into concrete indicies.
- * As connections are being made, some may be "star" connections which need to be resolved.
- * In some way to determine how many actual edges they correspond to.
- * We also need to build up the ranges of edges which correspond to each binding operator, so that
- * We can apply the correct edge parameters and later build up correct bundle connections.
- *
- * [[oPortMapping]]: `Seq[(Int, Int)]` where each item is the range of edges corresponding to that oPort (binding operator).
- * [[iPortMapping]]: `Seq[(Int, Int)]` where each item is the range of edges corresponding to that iPort (binding operator).
- * [[oStar]]: `Int` the value to return for this node `N` for any `N :*= foo` or `N :*=* foo :*= bar`
- * [[iStar]]: `Int` the value to return for this node `N` for any `foo :=* N` or `bar :=* foo :*=* N`
- */
- protected[diplomacy] lazy val (oPortMapping: Seq[(Int, Int)], iPortMapping: Seq[(Int, Int)], oStar: Int, iStar: Int) = {
- try {
- if (starCycleGuard) throw StarCycleException()
- starCycleGuard = true
- // For a given node N...
- // Number of foo :=* N
- // + Number of bar :=* foo :*=* N
- val oStars = oBindings.count { case (_,n,b,_,_) => b == BIND_STAR || (b == BIND_FLEX && edgeArityDirection(n) < 0) }
- // Number of N :*= foo
- // + Number of N :*=* foo :*= bar
- val iStars = iBindings.count { case (_,n,b,_,_) => b == BIND_STAR || (b == BIND_FLEX && edgeArityDirection(n) > 0) }
- // 1 for foo := N
- // + bar.iStar for bar :*= foo :*=* N
- // + foo.iStar for foo :*= N
- // + 0 for foo :=* N
- val oKnown = oBindings.map { case (_, n, b, _, _) => b match {
- case BIND_ONCE => 1
- case BIND_FLEX => edgeAritySelect(n, 0, n.iStar)
- case BIND_QUERY => n.iStar
- case BIND_STAR => 0 }}.sum
- // 1 for N := foo
- // + bar.oStar for N :*=* foo :=* bar
- // + foo.oStar for N :=* foo
- // + 0 for N :*= foo
- val iKnown = iBindings.map { case (_, n, b, _, _) => b match {
- case BIND_ONCE => 1
- case BIND_FLEX => edgeAritySelect(n, n.oStar, 0)
- case BIND_QUERY => n.oStar
- case BIND_STAR => 0 }}.sum
- // Resolve star depends on the node subclass to implement the algorithm for this.
- val (iStar, oStar) = resolveStar(iKnown, oKnown, iStars, oStars)
- // Cumulative list of resolved outward binding range starting points
- val oSum = oBindings.map { case (_, n, b, _, _) => b match {
- case BIND_ONCE => 1
- case BIND_FLEX => edgeAritySelect(n, oStar, n.iStar)
- case BIND_QUERY => n.iStar
- case BIND_STAR => oStar }}.scanLeft(0)(_+_)
- // Cumulative list of resolved inward binding range starting points
- val iSum = iBindings.map { case (_, n, b, _, _) => b match {
- case BIND_ONCE => 1
- case BIND_FLEX => edgeAritySelect(n, n.oStar, iStar)
- case BIND_QUERY => n.oStar
- case BIND_STAR => iStar }}.scanLeft(0)(_+_)
- // Create ranges for each binding based on the running sums and return
- // those along with resolved values for the star operations.
- (oSum.init zip oSum.tail, iSum.init zip iSum.tail, oStar, iStar)
- } catch {
- case c: StarCycleException => throw c.copy(loop = context +: c.loop)
- }
- }
-
- /** Sequence of inward ports.
- *
- * This should be called after all star bindings are resolved.
- *
- * Each element is:
- * `j` Port index of this binding in the Node's [[oPortMapping]] on the other side of the binding.
- * `n` Instance of inward node.
- * `p` View of [[Parameters]] where this connection was made.
- * `s` Source info where this connection was made in the source code.
- */
- protected[diplomacy] lazy val oDirectPorts: Seq[(Int, InwardNode[DO, UO, BO], Parameters, SourceInfo)] = oBindings.flatMap { case (i, n, _, p, s) =>
- // for each binding operator in this node, look at what it connects to
- val (start, end) = n.iPortMapping(i)
- (start until end) map { j => (j, n, p, s) }
- }
-
- /** Sequence of outward ports.
- *
- * This should be called after all star bindings are resolved.
- *
- * `j` Port index of this binding in the Node's [[oPortMapping]] on the other side of the binding.
- * `n` Instance of outward node.
- * `p` View of [[Parameters]] where this connection was made.
- * `s` [[SourceInfo]] where this connection was made in the source code.
- */
- protected[diplomacy] lazy val iDirectPorts: Seq[(Int, OutwardNode[DI, UI, BI], Parameters, SourceInfo)] = iBindings.flatMap { case (i, n, _, p, s) =>
- // query this port index range of this node in the other side of node.
- val (start, end) = n.oPortMapping(i)
- (start until end) map { j => (j, n, p, s) }
- }
-
- // Ephemeral nodes ( which have non-None iForward/oForward) have in_degree = out_degree
- // Thus, there must exist an Eulerian path and the below algorithms terminate
- @scala.annotation.tailrec
- private def oTrace(tuple: (Int, InwardNode[DO, UO, BO], Parameters, SourceInfo)): (Int, InwardNode[DO, UO, BO], Parameters, SourceInfo) =
- tuple match { case (i, n, p, s) => n.iForward(i) match {
- case None => (i, n, p, s)
- case Some ((j, m)) => oTrace((j, m, p, s))
- } }
-
- @scala.annotation.tailrec
- private def iTrace(tuple: (Int, OutwardNode[DI, UI, BI], Parameters, SourceInfo)): (Int, OutwardNode[DI, UI, BI], Parameters, SourceInfo) =
- tuple match { case (i, n, p, s) => n.oForward(i) match {
- case None => (i, n, p, s)
- case Some ((j, m)) => iTrace((j, m, p, s))
- } }
-
- /** Final output ports after all stars and port forwarding (e.g. [[EphemeralNode]]s) have been resolved.
- *
- * Each Port is a tuple of:
- * - Numeric index of this binding in the [[InwardNode]] on the other end.
- * - [[InwardNode]] on the other end of this binding.
- * - A view of [[Parameters]] where the binding occurred.
- * - [[SourceInfo]] for source-level error reporting.
- */
- lazy val oPorts: Seq[(Int, InwardNode[DO, UO, BO], Parameters, SourceInfo)] = oDirectPorts.map(oTrace)
-
- /** Final input ports after all stars and port forwarding (e.g. [[EphemeralNode]]s) have been resolved.
- *
- * Each Port is a tuple of:
- * - numeric index of this binding in [[OutwardNode]] on the other end.
- * - [[OutwardNode]] on the other end of this binding.
- * - a view of [[Parameters]] where the binding occurred.
- * - [[SourceInfo]] for source-level error reporting.
- */
- lazy val iPorts: Seq[(Int, OutwardNode[DI, UI, BI], Parameters, SourceInfo)] = iDirectPorts.map(iTrace)
-
- private var oParamsCycleGuard = false
- protected[diplomacy] lazy val diParams: Seq[DI] = iPorts.map { case (i, n, _, _) => n.doParams(i) }
- protected[diplomacy] lazy val doParams: Seq[DO] = {
- try {
- if (oParamsCycleGuard) throw DownwardCycleException()
- oParamsCycleGuard = true
- val o = mapParamsD(oPorts.size, diParams)
- require (o.size == oPorts.size,
- s"""Diplomacy has detected a problem with your graph:
- |At the following node, the number of outward ports should equal the number of produced outward parameters.
- |$context
- |$connectedPortsInfo
- |Downstreamed inward parameters: [${diParams.mkString(",")}]
- |Produced outward parameters: [${o.mkString(",")}]
- |""".stripMargin)
- o.map(outer.mixO(_, this))
- } catch {
- case c: DownwardCycleException => throw c.copy(loop = context +: c.loop)
- }
- }
-
- private var iParamsCycleGuard = false
- protected[diplomacy] lazy val uoParams: Seq[UO] = oPorts.map { case (o, n, _, _) => n.uiParams(o) }
- protected[diplomacy] lazy val uiParams: Seq[UI] = {
- try {
- if (iParamsCycleGuard) throw UpwardCycleException()
- iParamsCycleGuard = true
- val i = mapParamsU(iPorts.size, uoParams)
- require (i.size == iPorts.size,
- s"""Diplomacy has detected a problem with your graph:
- |At the following node, the number of inward ports should equal the number of produced inward parameters.
- |$context
- |$connectedPortsInfo
- |Upstreamed outward parameters: [${uoParams.mkString(",")}]
- |Produced inward parameters: [${i.mkString(",")}]
- |""".stripMargin)
- i.map(inner.mixI(_, this))
- } catch {
- case c: UpwardCycleException => throw c.copy(loop = context +: c.loop)
- }
- }
-
- /** Outward edge parameters. */
- protected[diplomacy] lazy val edgesOut: Seq[EO] = (oPorts zip doParams).map { case ((i, n, p, s), o) => outer.edgeO(o, n.uiParams(i), p, s) }
-
- /** Inward edge parameters. */
- protected[diplomacy] lazy val edgesIn: Seq[EI] = (iPorts zip uiParams).map { case ((o, n, p, s), i) => inner.edgeI(n.doParams(o), i, p, s) }
-
- /** A tuple of the input edge parameters and output edge parameters for the edges bound to this node.
- *
- * If you need to access to the edges of a foreign Node, use this method (in/out create bundles).
- */
- lazy val edges: Edges[EI, EO] = Edges(edgesIn, edgesOut)
-
- /** Create actual Wires corresponding to the Bundles parameterized by the outward edges of this node. */
- protected[diplomacy] lazy val bundleOut: Seq[BO] = edgesOut.map { e =>
- val x = Wire(outer.bundleO(e)).suggestName(s"${valName.name}Out")
- // TODO: Don't care unconnected forwarded diplomatic signals for compatibility issue,
- // In the future, we should add an option to decide whether allowing unconnected in the LazyModule
- x := DontCare
- x
- }
-
- /** Create actual Wires corresponding to the Bundles parameterized by the inward edges of this node. */
- protected[diplomacy] lazy val bundleIn: Seq[BI] = edgesIn .map { e =>
- val x = Wire(inner.bundleI(e)).suggestName(s"${valName.name}In")
- // TODO: Don't care unconnected forwarded diplomatic signals for compatibility issue,
- // In the future, we should add an option to decide whether allowing unconnected in the LazyModule
- x := DontCare
- x
- }
-
- private def emptyDanglesOut: Seq[Dangle] = oPorts.zipWithIndex.map { case ((j, n, _, _), i) =>
- Dangle(
- source = HalfEdge(serial, i),
- sink = HalfEdge(n.serial, j),
- flipped= false,
- name = wirePrefix + "out",
- dataOpt= None)
- }
- private def emptyDanglesIn: Seq[Dangle] = iPorts.zipWithIndex.map { case ((j, n, _, _), i) =>
- Dangle(
- source = HalfEdge(n.serial, j),
- sink = HalfEdge(serial, i),
- flipped= true,
- name = wirePrefix + "in",
- dataOpt=None)
- }
-
-
- /** Create the [[Dangle]]s which describe the connections from this node output to other nodes inputs. */
- protected[diplomacy] def danglesOut: Seq[Dangle] = emptyDanglesOut.zipWithIndex.map {
- case (d,i) => d.copy(dataOpt = Some(bundleOut(i)))
- }
-
- /** Create the [[Dangle]]s which describe the connections from this node input from other nodes outputs. */
- protected[diplomacy] def danglesIn: Seq[Dangle] = emptyDanglesIn.zipWithIndex.map {
- case (d,i) => d.copy(dataOpt = Some(bundleIn(i)))
- }
-
- private[diplomacy] var instantiated = false
-
- /** Gather Bundle and edge parameters of outward ports.
- *
- * Accessors to the result of negotiation to be used within
- * [[LazyModuleImp]] Code. Should only be used within [[LazyModuleImp]] code
- * or after its instantiation has completed.
- */
- def out: Seq[(BO, EO)] = {
- require(instantiated, s"$name.out should not be called until after instantiation of its parent LazyModule.module has begun")
- bundleOut zip edgesOut
- }
-
- /** Gather Bundle and edge parameters of inward ports.
- *
- * Accessors to the result of negotiation to be used within
- * [[LazyModuleImp]] Code. Should only be used within [[LazyModuleImp]] code
- * or after its instantiation has completed.
- */
- def in: Seq[(BI, EI)] = {
- require(instantiated, s"$name.in should not be called until after instantiation of its parent LazyModule.module has begun")
- bundleIn zip edgesIn
- }
-
- /** Actually instantiate this node during [[LazyModuleImp]] evaluation.
- * Mark that it's safe to use the Bundle wires,
- * instantiate monitors on all input ports if appropriate,
- * and return all the dangles of this node.
- */
- protected[diplomacy] def instantiate(): Seq[Dangle] = {
- instantiated = true
- if (!circuitIdentity) {
- (iPorts zip in) foreach {
- case ((_, _, p, _), (b, e)) => if (p(MonitorsEnabled)) inner.monitor(b, e)
- } }
- danglesOut ++ danglesIn
- }
-
- protected[diplomacy] def cloneDangles(): Seq[Dangle] = emptyDanglesOut ++ emptyDanglesIn
-
- /** Connects the outward part of a node with the inward part of this node. */
- protected[diplomacy] def bind(h: OutwardNode[DI, UI, BI], binding: NodeBinding)(implicit p: Parameters, sourceInfo: SourceInfo): Unit = {
- val x = this // x := y
- val y = h
- val info = sourceLine(sourceInfo, " at ", "")
- val i = x.iPushed
- 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)
- }
-
- /* Metadata for printing the node graph. */
- def inputs: Seq[(OutwardNode[DI, UI, BI], RenderedEdge)] = (iPorts zip edgesIn) map { case ((_, n, p, _), e) =>
- val re = inner.render(e)
- (n, re.copy(flipped = re.flipped != p(RenderFlipped)))
- }
- /** Metadata for printing the node graph */
- def outputs: Seq[(InwardNode[DO, UO, BO], RenderedEdge)] = oPorts map { case (i, n, _, _) => (n, n.inputs(i)._2) }
-}
-
-/** A [[MixedNode]] that may be extended with custom behavior. */
-abstract class MixedCustomNode[DI, UI, EI, BI <: Data, DO, UO, EO, BO <: Data](
- inner: InwardNodeImp [DI, UI, EI, BI],
- outer: OutwardNodeImp[DO, UO, EO, BO])(
- implicit valName: ValName)
- extends MixedNode(inner, outer) {
- override def description = "custom"
- def resolveStar(iKnown: Int, oKnown: Int, iStars: Int, oStars: Int): (Int, Int)
- def mapParamsD(n: Int, p: Seq[DI]): Seq[DO]
- def mapParamsU(n: Int, p: Seq[UO]): Seq[UI]
-}
-
-/** A [[NodeImp]] that may be extended with custom behavior.
- *
- * Different from a [[MixedNode]] in that the inner and outer [[NodeImp]]s are the same.
- */
-abstract class CustomNode[D, U, EO, EI, B <: Data](imp: NodeImp[D, U, EO, EI, B])(
- implicit valName: ValName)
- extends MixedCustomNode(imp, imp)
-
-/** A JunctionNode creates multiple parallel arbiters.
- *
- * @example
- * {{{
- * val jbar = LazyModule(new JBar)
- * slave1.node := jbar.node
- * slave2.node := jbar.node
- * extras.node :=* jbar.node
- * jbar.node :*= masters1.node
- * jbar.node :*= masters2.node
- * }}}
- *
- * In the above example, only the first two connections have their multiplicity specified.
- * All the other connections include a '*' on the JBar's side, so the JBar decides the multiplicity.
- * Thus, in this example, we get 2x crossbars with 2 masters like this:
- * {slave1, extras.1} <= jbar.1 <= {masters1.1, masters2.1}
- * {slave2, extras.2} <= jbar.2 <= {masters1.2, masters2,2}
- *
- * @example
- * {{{
- * val jbar = LazyModule(new JBar)
- * jbar.node :=* masters.node
- * slaves1.node :=* jbar.node
- * slaves2.node :=* jbar.node
- * }}}
- * In the above example, the first connection takes multiplicity (*) from the right (masters).
- * Supposing masters.node had 3 edges, this would result in these three arbiters:
- * {slaves1.1, slaves2.1} <= jbar.1 <= { masters.1 }
- * {slaves1.2, slaves2.2} <= jbar.2 <= { masters.2 }
- * {slaves1.3, slaves2.3} <= jbar.3 <= { masters.3 }
- */
-class MixedJunctionNode[DI, UI, EI, BI <: Data, DO, UO, EO, BO <: Data](
- inner: InwardNodeImp [DI, UI, EI, BI],
- outer: OutwardNodeImp[DO, UO, EO, BO])(
- dFn: Seq[DI] => Seq[DO],
- uFn: Seq[UO] => Seq[UI])(
- implicit valName: ValName)
- extends MixedNode(inner, outer) {
- protected[diplomacy] var multiplicity = 0
-
- def uRatio: Int = iPorts.size / multiplicity
- def dRatio: Int = oPorts.size / multiplicity
-
- override def description = "junction"
- protected[diplomacy] def resolveStar(iKnown: Int, oKnown: Int, iStars: Int, oStars: Int): (Int, Int) = {
- require (iKnown == 0 || oKnown == 0,
- s"""Diplomacy has detected a problem with your graph:
- |The following node appears left of a :=* or a := and right of a :*= or :=. Only one side may drive multiplicity.
- |$context
- |$bindingInfo
- |""".stripMargin)
- multiplicity = iKnown max oKnown
- (multiplicity, multiplicity)
- }
- protected[diplomacy] def mapParamsD(n: Int, p: Seq[DI]): Seq[DO] =
- p.grouped(multiplicity).toList.transpose.map(dFn).transpose.flatten
- protected[diplomacy] def mapParamsU(n: Int, p: Seq[UO]): Seq[UI] =
- p.grouped(multiplicity).toList.transpose.map(uFn).transpose.flatten
-
- def inoutGrouped: Seq[(Seq[(BI, EI)], Seq[(BO, EO)])] = {
- val iGroups = in .grouped(multiplicity).toList.transpose
- val oGroups = out.grouped(multiplicity).toList.transpose
- iGroups zip oGroups
- }
-}
-
-/** A node type which has a fixed ratio between the number of input edges and output edges.
- *
- * The [[NodeImp]] on either side is the same.
- *
- * One example usage would be for putting down a series of 2:1 arbiters.
- *
- * Suppose you had N banks of L2 and wanted to connect those to two different driver crossbars.
- * In that case you can do this:
- * {{{
- * l2banks.node :*= jbar.node
- * jbar.node :*= xbar1.node
- * jbar.node :*= xbar2.node
- * }}}
- * If the L2 has 4 banks, now there are 4 egress ports on both xbar1 and xbar2 and they are arbitrated by the jbar.
- */
-class JunctionNode[D, U, EO, EI, B <: Data](imp: NodeImp[D, U, EO, EI, B])(
- dFn: Seq[D] => Seq[D],
- uFn: Seq[U] => Seq[U])(
- implicit valName: ValName)
- extends MixedJunctionNode[D, U, EI, B, D, U, EO, B](imp, imp)(dFn, uFn)
-
-/** [[MixedAdapterNode]] is used to transform between different diplomacy protocols ([[NodeImp]]), without changing the number of edges passing through it.
- *
- * For example, a [[MixedAdapterNode]] is needed for a TL to AXI bridge (interface).
- * {{{
- * case class TLToAXI4Node(stripBits: Int = 0)(implicit valName: ValName) extends MixedAdapterNode(TLImp, AXI4Imp)
- * }}}
- *
- * @param dFn convert downward parameter from input to output.
- * @param uFn convert upward parameter from output to input.
- */
-class MixedAdapterNode[DI, UI, EI, BI <: Data, DO, UO, EO, BO <: Data](
- inner: InwardNodeImp [DI, UI, EI, BI],
- outer: OutwardNodeImp[DO, UO, EO, BO])(
- dFn: DI => DO,
- uFn: UO => UI)(
- implicit valName: ValName)
- extends MixedNode(inner, outer) {
- override def description = "adapter"
- protected[diplomacy] override def flexibleArityDirection = true
- protected[diplomacy] def resolveStar(iKnown: Int, oKnown: Int, iStars: Int, oStars: Int): (Int, Int) = {
- require (oStars + iStars <= 1,
- s"""Diplomacy has detected a problem with your graph:
- |The following node appears left of a :*= $iStars times and right of a :=* $oStars times, at most once is allowed.
- |$context
- |$bindingInfo
- |""".stripMargin)
- if (oStars > 0) {
- require (iKnown >= oKnown,
- s"""Diplomacy has detected a problem with your graph:
- |After being connected right of :=*, the following node appears left of a := $iKnown times and right of a := $oKnown times.
- |${iKnown - oKnown} additional right of := bindings are required to resolve :=* successfully.
- |$context
- |$bindingInfo
- |""".stripMargin)
- (0, iKnown - oKnown)
- } else if (iStars > 0) {
- require (oKnown >= iKnown,
- s"""Diplomacy has detected a problem with your graph:
- |After being connected left of :*=, the following node appears left of a := $iKnown times and right of a := $oKnown times.
- |${oKnown - iKnown} additional left := bindings are required to resolve :*= successfully.
- |$context
- |$bindingInfo
- |""".stripMargin)
- (oKnown - iKnown, 0)
- } else {
- require (oKnown == iKnown,
- s"""Diplomacy has detected a problem with your graph:
- |The following node appears left of a := $iKnown times and right of a := $oKnown times.
- |Either the number of bindings on both sides of the node match, or connect this node by left-hand side of :*= or right-hand side of :=*
- |$context
- |$bindingInfo
- |""".stripMargin)
- (0, 0)
- }
- }
- protected[diplomacy] def mapParamsD(n: Int, p: Seq[DI]): Seq[DO] = {
- require(n == p.size,
- s"""Diplomacy has detected a problem with your graph:
- |The following node has ${p.size} inputs and $n outputs, they must match.
- |$context
- |$bindingInfo
- |""".stripMargin)
- p.map(dFn)
- }
- protected[diplomacy] def mapParamsU(n: Int, p: Seq[UO]): Seq[UI] = {
- require(n == p.size,
- s"""Diplomacy has detected a problem with your graph:
- |The following node has $n inputs and ${p.size} outputs, they must match
- |$context
- |$bindingInfo
- |""".stripMargin)
- p.map(uFn)
- }
-}
-
-/** A node which modifies the parameters flowing through it, but without changing the number of edges or the diplomatic protocol implementation. */
-class AdapterNode[D, U, EO, EI, B <: Data](imp: NodeImp[D, U, EO, EI, B])(
- dFn: D => D,
- uFn: U => U)(
- implicit valName: ValName)
- extends MixedAdapterNode[D, U, EI, B, D, U, EO, B](imp, imp)(dFn, uFn)
-
-/** A node which does not modify the parameters nor the protocol for edges that pass through it.
- *
- * During hardware generation, [[IdentityNode]]s automatically connect their inputs to outputs.
- */
-class IdentityNode[D, U, EO, EI, B <: Data](imp: NodeImp[D, U, EO, EI, B])()(implicit valName: ValName)
- extends AdapterNode(imp)({ s => s }, { s => s }) {
- override def description = "identity"
- override final def circuitIdentity = true
- override protected[diplomacy] def instantiate(): Seq[Dangle] = {
- val dangles = super.instantiate()
- (out zip in) foreach { case ((o, _), (i, _)) => o :<>= i }
- dangles
- }
- override protected[diplomacy] def cloneDangles(): Seq[Dangle] = super.cloneDangles()
-}
-
-/** [[EphemeralNode]]s are used as temporary connectivity placeholders, but disappear from the final node graph.
- * An ephemeral node provides a mechanism to directly connect two nodes to each other where neither node knows about the other,
- * but both know about an ephemeral node they can use to facilitate the connection.
- */
-class EphemeralNode[D, U, EO, EI, B <: Data](imp: NodeImp[D, U, EO, EI, B])()(implicit valName: ValName)
- extends AdapterNode(imp)({ s => s }, { s => s }) {
- override def description = "ephemeral"
- override final def circuitIdentity = true
- override def omitGraphML = true
- override def oForward(x: Int): Option[(Int, OutwardNode[D, U, B])] = Some(iDirectPorts(x) match { case (i, n, _, _) => (i, n) })
- override def iForward(x: Int): Option[(Int, InwardNode[D, U, B])] = Some(oDirectPorts(x) match { case (i, n, _, _) => (i, n) })
- override protected[diplomacy] def instantiate(): Seq[Dangle] = {
- instantiated = true
- Nil
- }
- override protected[diplomacy] def cloneDangles(): Seq[Dangle] = Nil
-}
-
-/** [[MixedNexusNode]] is used when the number of nodes connecting from either side is unknown (e.g. a Crossbar which also is a protocol adapter).
- *
- * The [[NodeImp]] is different between [[inner]] and [[outer]],
- *
- * @param dFn Function for mapping the parameters flowing downward into new outward flowing down parameters.
- * @param uFn Function for mapping the parameters flowing upward into new inward flowing up parameters.
- * @param inputRequiresOutput True if it is required that if there are input connections, there are output connections (this node can't just be a sink).
- * @param outputRequiresInput True if it is required that if there are output connections, there are input connections (this node can't just be a source).
- */
-class MixedNexusNode[DI, UI, EI, BI <: Data, DO, UO, EO, BO <: Data](
- inner: InwardNodeImp [DI, UI, EI, BI],
- outer: OutwardNodeImp[DO, UO, EO, BO])(
- dFn: Seq[DI] => DO,
- uFn: Seq[UO] => UI,
- // no inputs and no outputs is always allowed
- inputRequiresOutput: Boolean = true,
- outputRequiresInput: Boolean = true)(
- implicit valName: ValName)
- extends MixedNode(inner, outer)
-{
- override def description = "nexus"
- protected[diplomacy] def resolveStar(iKnown: Int, oKnown: Int, iStars: Int, oStars: Int): (Int, Int) = {
- // a nexus treats :=* as a weak pointer
- def resolveStarInfo: String =
- s"""$context
- |$bindingInfo
- |number of known := bindings to inward nodes: $iKnown
- |number of known := bindings to outward nodes: $oKnown
- |number of binding queries from inward nodes: $iStars
- |number of binding queries from outward nodes: $oStars
- |""".stripMargin
- require(!outputRequiresInput || oKnown == 0 || iStars + iKnown != 0,
- s"""Diplomacy has detected a problem with your graph:
- |The following node has $oKnown outward connections and no inward connections. At least one inward connection was required.
- |$resolveStarInfo
- |""".stripMargin)
- require(!inputRequiresOutput || iKnown == 0 || oStars + oKnown != 0,
- s"""Diplomacy has detected a problem with your graph:
- |The following node node has $iKnown inward connections and no outward connections. At least one outward connection was required.
- |$resolveStarInfo
- |""".stripMargin)
- if (iKnown == 0 && oKnown == 0) (0, 0) else (1, 1)
- }
- protected[diplomacy] def mapParamsD(n: Int, p: Seq[DI]): Seq[DO] = { if (n > 0) { val a = dFn(p); Seq.fill(n)(a) } else Nil }
- protected[diplomacy] def mapParamsU(n: Int, p: Seq[UO]): Seq[UI] = { if (n > 0) { val a = uFn(p); Seq.fill(n)(a) } else Nil }
-}
-
-/** [[NexusNode]] is a [[MixedNexusNode]], in which the inward and outward side of the node have the same [[NodeImp]] implementation. */
-class NexusNode[D, U, EO, EI, B <: Data](imp: NodeImp[D, U, EO, EI, B])(
- dFn: Seq[D] => D,
- uFn: Seq[U] => U,
- inputRequiresOutput: Boolean = true,
- outputRequiresInput: Boolean = true)(
- implicit valName: ValName)
- extends MixedNexusNode[D, U, EI, B, D, U, EO, B](imp, imp)(dFn, uFn, inputRequiresOutput, outputRequiresInput)
-
-/** A node which represents a node in the graph which only has outward edges and no inward edges.
- *
- * A [[SourceNode]] cannot appear left of a `:=`, `:*=`, `:=*, or `:*=*`
- * There are no Mixed [[SourceNode]]s, There are no "Mixed" [[SourceNode]]s because each one only has an outward side.
- */
-class SourceNode[D, U, EO, EI, B <: Data](imp: NodeImp[D, U, EO, EI, B])(po: Seq[D])(implicit valName: ValName)
- extends MixedNode(imp, imp)
-{
- override def description = "source"
- protected[diplomacy] def resolveStar(iKnown: Int, oKnown: Int, iStars: Int, oStars: Int): (Int, Int) = {
- def resolveStarInfo: String =
- s"""$context
- |$bindingInfo
- |number of known := bindings to inward nodes: $iKnown
- |number of known := bindings to outward nodes: $oKnown
- |number of binding queries from inward nodes: $iStars
- |number of binding queries from outward nodes: $oStars
- |${po.size} outward parameters: [${po.map(_.toString).mkString(",")}]
- |""".stripMargin
- require(oStars <= 1,
- s"""Diplomacy has detected a problem with your graph:
- |The following node appears right of a :=* $oStars times; at most once is allowed.
- |$resolveStarInfo
- |""".stripMargin)
- require(iStars == 0,
- s"""Diplomacy has detected a problem with your graph:
- |The following node cannot appear left of a :*=
- |$resolveStarInfo
- |""".stripMargin)
- require(iKnown == 0,
- s"""Diplomacy has detected a problem with your graph:
- |The following node cannot appear left of a :=
- |$resolveStarInfo
- |""".stripMargin)
- if (oStars == 0)
- require(po.size == oKnown,
- s"""Diplomacy has detected a problem with your graph:
- |The following node has $oKnown outward bindings connected to it, but ${po.size} sources were specified to the node constructor.
- |Either the number of outward := bindings should be exactly equal to the number of sources, or connect this node on the right-hand side of a :=*
- |$resolveStarInfo
- |""".stripMargin)
- else
- require(po.size >= oKnown,
- s"""Diplomacy has detected a problem with your graph:
- |The following node has $oKnown outward bindings connected to it, but ${po.size} sources were specified to the node constructor.
- |To resolve :=*, size of outward parameters can not be less than bindings.
- |$resolveStarInfo
- |""".stripMargin
- )
- (0, po.size - oKnown)
- }
- protected[diplomacy] def mapParamsD(n: Int, p: Seq[D]): Seq[D] = po
- protected[diplomacy] def mapParamsU(n: Int, p: Seq[U]): Seq[U] = Seq()
-
- def makeIOs()(implicit valName: ValName): HeterogeneousBag[B] = {
- val bundles = this.out.map(_._1)
- val ios = IO(Flipped(new HeterogeneousBag(bundles)))
- ios.suggestName(valName.name)
- bundles.zip(ios).foreach { case (bundle, io) => bundle <> io }
- ios
- }
-}
-
-/** A node which represents a node in the graph which has only inward edges, no outward edges.
- *
- * A [[SinkNode]] cannot appear cannot appear right of a `:=`, `:*=`, `:=*`, or `:*=*`
- *
- * There are no "Mixed" [[SinkNode]]s because each one only has an inward side.
- */
-class SinkNode[D, U, EO, EI, B <: Data](imp: NodeImp[D, U, EO, EI, B])(pi: Seq[U])(implicit valName: ValName)
- extends MixedNode(imp, imp)
-{
- override def description = "sink"
- protected[diplomacy] def resolveStar(iKnown: Int, oKnown: Int, iStars: Int, oStars: Int): (Int, Int) = {
- def resolveStarInfo: String =
- s"""$context
- |$bindingInfo
- |number of known := bindings to inward nodes: $iKnown
- |number of known := bindings to outward nodes: $oKnown
- |number of binding queries from inward nodes: $iStars
- |number of binding queries from outward nodes: $oStars
- |${pi.size} inward parameters: [${pi.map(_.toString).mkString(",")}]
- |""".stripMargin
- require (iStars <= 1,
- s"""Diplomacy has detected a problem with your graph:
- |The following node appears left of a :*= $iStars times; at most once is allowed.
- |$resolveStarInfo
- |""".stripMargin)
- require (oStars == 0,
- s"""Diplomacy has detected a problem with your graph:
- |The following node cannot appear right of a :=*
- |$resolveStarInfo
- |""".stripMargin)
- require (oKnown == 0,
- s"""Diplomacy has detected a problem with your graph:
- |The following node cannot appear right of a :=
- |$resolveStarInfo
- |""".stripMargin)
- if (iStars == 0)
- require(pi.size == iKnown,
- s"""Diplomacy has detected a problem with your graph:
- |The following node has $iKnown inward bindings connected to it, but ${pi.size} sinks were specified to the node constructor.
- |Either the number of inward := bindings should be exactly equal to the number of sink, or connect this node on the left-hand side of a :*=
- |$resolveStarInfo
- |""".stripMargin)
- else
- require(pi.size >= iKnown,
- s"""Diplomacy has detected a problem with your graph:
- |The following node has $iKnown inward bindings connected to it, but ${pi.size} sinks were specified to the node constructor.
- |To resolve :*=, size of inward parameters can not be less than bindings.
- |$resolveStarInfo
- |""".stripMargin
- )
- (pi.size - iKnown, 0)
- }
- protected[diplomacy] def mapParamsD(n: Int, p: Seq[D]): Seq[D] = Seq()
- protected[diplomacy] def mapParamsU(n: Int, p: Seq[U]): Seq[U] = pi
-
- def makeIOs()(implicit valName: ValName): HeterogeneousBag[B] = {
- val bundles = this.in.map(_._1)
- val ios = IO(new HeterogeneousBag(bundles))
- ios.suggestName(valName.name)
- bundles.zip(ios).foreach { case (bundle, io) => io <> bundle }
- ios
- }
-}
-
-/** A node intended to replace a portion of the diplomatic graph in order to test functionality of a copy (cloned) [[LazyModule]]
- *
- * @param node the node to copy
- * @param clone the copy of the LazyModule containing [[node]]
- */
-class MixedTestNode[DI, UI, EI, BI <: Data, DO, UO, EO, BO <: Data] protected[diplomacy](
- node: NodeHandle [DI, UI, EI, BI, DO, UO, EO, BO], clone: CloneLazyModule)(
- implicit valName: ValName)
- extends MixedNode(node.inner, node.outer)
-{
- // The devices connected to this test node must recreate these parameters:
- def iParams: Seq[DI] = node.inward .diParams
- def oParams: Seq[UO] = node.outward.uoParams
-
- override def description = "test"
- protected[diplomacy] def resolveStar(iKnown: Int, oKnown: Int, iStars: Int, oStars: Int): (Int, Int) = {
- def resolveStarInfo: String =
- s"""$context
- |$bindingInfo
- |number of known := bindings to inward nodes: $iKnown
- |number of known := bindings to outward nodes: $oKnown
- |number of binding queries from inward nodes: $iStars
- |number of binding queries from outward nodes: $oStars
- |downstream inward parameters: ${node.inward.diParams}
- |upstream inward parameters: ${node.inward.uiParams}
- |upstream outward parameters: ${node.outward.uoParams}
- |downstream outward parameters: ${node.outward.doParams}
- |node.inward.uiParams.size
- |""".stripMargin
-
- require(oStars <= 1,
- s"""Diplomacy has detected a problem with your graph:
- |The following node appears right of a :=* $oStars times; at most once is allowed.
- |$resolveStarInfo
- |""".stripMargin)
- require(iStars <= 1,
- s"""Diplomacy has detected a problem with your graph:
- |The following node appears left of a :*= $iStars times; at most once is allowed.
- |$resolveStarInfo
- |""".stripMargin)
- require(node.inward .uiParams.size == iKnown || iStars == 1,
- s"""Diplomacy has detected a problem with your graph:
- |The following node has only $iKnown inputs, which should be ${node.inward.uiParams.size}, or connect this node on the left-hand side of :*=
- |$resolveStarInfo
- |""".stripMargin)
- require(node.outward.doParams.size == oKnown || oStars == 1,
- s"""Diplomacy has detected a problem with your graph:
- |The following node has only $oKnown outputs, which should be ${node.outward.doParams.size}, or connect this node on the right-hand side of :=*
- |$resolveStarInfo
- |""".stripMargin)
- (node.inward.uiParams.size - iKnown, node.outward.doParams.size - oKnown)
- }
-
- protected[diplomacy] def mapParamsU(n: Int, p: Seq[UO]): Seq[UI] = node.inward .uiParams
- protected[diplomacy] def mapParamsD(n: Int, p: Seq[DI]): Seq[DO] = node.outward.doParams
-
- override protected[diplomacy] def instantiate(): Seq[Dangle] = {
- val dangles = super.instantiate()
- val orig_module = clone.base.module
- val clone_auto = clone.io("auto").asInstanceOf[AutoBundle]
-
- danglesOut.zipWithIndex.foreach { case (d, i) =>
- val orig = orig_module.dangles.find(_.source == HalfEdge(node.outward.serial, i))
- require (orig.isDefined, s"Cloned node ${node.outward.name} must be connected externally out ${orig_module.name}")
- val io_name = orig_module.auto.elements.find(_._2 eq orig.get.data).get._1
- d.data <> clone_auto.elements(io_name)
- }
- danglesIn.zipWithIndex.foreach { case (d, i) =>
- val orig = orig_module.dangles.find(_.sink == HalfEdge(node.inward.serial, i))
- require (orig.isDefined, s"Cloned node ${node.inward.name} must be connected externally in ${orig_module.name}")
- val io_name = orig_module.auto.elements.find(_._2 eq orig.get.data).get._1
- clone_auto.elements(io_name) <> d.data
- }
-
- dangles
- }
- override protected[diplomacy] def cloneDangles(): Seq[Dangle] = {
- require(false, "Unsupported")
- super.cloneDangles()
- }
-}
diff --git a/src/main/scala/diplomacy/Resources.scala b/src/main/scala/diplomacy/Resources.scala
index 4dc59d9530..78a23ae188 100644
--- a/src/main/scala/diplomacy/Resources.scala
+++ b/src/main/scala/diplomacy/Resources.scala
@@ -280,7 +280,7 @@ trait BindingScope
private case class ExpandedValue(path: Seq[String], labels: Seq[String], value: Seq[ResourceValue])
private lazy val eval: Unit = {
- require (!LazyModule.scope.isDefined, "May not evaluate binding while still constructing LazyModules")
+ require (!LazyModule.getScope.isDefined, "May not evaluate binding while still constructing LazyModules")
parentScope.foreach { _.eval }
resourceBindings = parentScope.map(_.resourceBindings).getOrElse(Nil)
BindingScope.active = Some(this)
@@ -388,9 +388,9 @@ trait BindingScope
object BindingScope
{
protected[diplomacy] var active: Option[BindingScope] = None
- protected[diplomacy] def find(m: Option[LazyModule] = LazyModule.scope): Option[BindingScope] = m.flatMap {
- case x: BindingScope => find(x.parent).orElse(Some(x))
- case x => find(x.parent)
+ protected[diplomacy] def find(m: Option[LazyModule] = LazyModule.getScope): Option[BindingScope] = m.flatMap {
+ case x: BindingScope => find(x.getParent).orElse(Some(x))
+ case x => find(x.getParent)
}
var bindingScopes = new collection.mutable.ArrayBuffer[BindingScope]()
diff --git a/src/main/scala/diplomacy/ValName.scala b/src/main/scala/diplomacy/ValName.scala
deleted file mode 100644
index bf0e581229..0000000000
--- a/src/main/scala/diplomacy/ValName.scala
+++ /dev/null
@@ -1,12 +0,0 @@
-// See LICENSE.SiFive for license details.
-
-package freechips.rocketchip.diplomacy
-
-import freechips.rocketchip.macros.ValNameImpl
-
-case class ValName(name: String)
-
-object ValName
-{
- implicit def materialize(implicit x: ValNameImpl): ValName = ValName(x.name)
-}
diff --git a/src/main/scala/diplomacy/package.scala b/src/main/scala/diplomacy/package.scala
index 5433147fae..0453f7c924 100644
--- a/src/main/scala/diplomacy/package.scala
+++ b/src/main/scala/diplomacy/package.scala
@@ -2,190 +2,15 @@
package freechips.rocketchip
-import chisel3.experimental.{SourceInfo, SourceLine}
import chisel3.Data
+import chisel3.experimental.{SourceInfo, SourceLine}
import org.chipsalliance.cde.config.Parameters
-import scala.language.implicitConversions
+import scala.language.implicitConversions
-/** Diplomacy is a set of abstractions for describing directed, acyclic graphs
- * where parameters will be negotiated between nodes. These abstractions are
- * expressed in the form of abstract classes, traits, and type parameters, which
- * comprises nearly all of the types defined in this package.
- *
- * The [[NodeImp]] ("node implementation") is the main abstract type that associates
- * the type parameters of all other abstract types. Defining a concrete
- * implementation of [[NodeImp]] will therefore determine concrete types for all
- * type parameters. For example, passing in a concrete instance of NodeImp to a
- * SourceNode will fully determine concrete types for all of a SourceNode's type
- * parameters.
- *
- * Specific applications of Diplomacy are expected to either extend these types
- * or to specify concrete types for the type parameters. This allows for
- * creating and associating application-specific node, edge, parameter, and bundle types.
- *
- *
- * =Concepts, metaphors, and mnemonics to help with understanding Diplomacy code=
- *
- * ==Parameter Types==
- *
- * There are several types of parameters involved in diplomacy code.
- *
- * - Upward-flowing/Downward-flowing Parameters: These parameter types flow along edges and can be considered as the
- * pre-negotiated, unresolved parameters.
- * - Edge Parameters: These parameters are the result of the diplomatic negotiation and that is resolved for each edge.
- * They are metadata, or an abstract concept of the connection represented by their edge, and contain any sort.
- * These are an abstract concept which carry any sort of conceptual information that is useful to pass along the graph edge.
- * For example, the full address map visible from a given edge and the supported access types for each memory region.
- * - "p" Parameters: These are parameters of type [[Parameters]] which are implicit and generally available
- * in various stages of the diplomacy codebase.
- * Often they are captured from the context in which a particular diplomatic node or edge is created or bound.
- * - Bundle Parameters: These parameters are used for actual hardware generation of the [[chisel3.Data]]s which connect
- * diplomatic components. In contrast to edge parameters, this may carry information like the width of an address
- * or opcode field.
- * While they are derived from Edge parameters holding all metadata computed over an edge,
- * Bundle parameters often contain only concrete information required to create the hardware type,
- * such as [[freechips.rocketchip.tilelink.TLBundleParameters]] and [[freechips.rocketchip.amba.axi4.AXI4BundleParameters]]
- *
- * ==Inward/Outward vs. Upward/Downward==
- *
- * Diplomacy defines two dimensions: inward/outward and upward/downward.
- *
- * Inward/outward refer to the direction of edges from the perspective of a given node.
- * For a given node:
- * - Inward refers to edges that point into itself.
- * - Outward refers to edges that point out from itself.
- *
- * Therefore, a given edge is always described as inward to one node and as outward from another.
- *
- * Upward/downward refer to the direction of the overall directed acyclic graph.
- * Because each each edge is directed, we say that the directions flow from sources (nodes that only have outward edges)
- * downwards to sinks (nodes that only have inward edges), or from sinks upwards to sources.
- * These terms are used in parameter negotiation, where parameters flow both
- * upwards and downwards on edges. Note that diplomacy avoids terms like "master/slave",
- * "producer/consumer", though these can be defined by the concrete implementations of diplomatic systems.
- * Such terms imply something about the transactional behavior of agents within a protocol,
- * whereas source/sink and up/down refer only to the structure of the graph and the flow of parameters.
- * - Upward refers to the flow of parameters along edges in the upwards direction.
- * - Downward refers to a flow of parameters along edges in the downwards direction.
- *
- * A useful mnemonic for distinguishing between upward and downward is to imagine
- * a diplomatic graph as a literal network of rivers where water flows in the direction of the edges,
- * and parameters that move in the upstream direction,
- * while downward refers to parameters that move in the downstream direction.
- *
- * ==Acronyms==
- *
- * Diplomacy has some commonly used acronyms described below:
- * D[IO], U[IO], E[IO], B[IO] are the types of parameters which will be propagated.
- * D: Downwards -- parameters passed in the same direction as the edge.
- * U: Upwards -- parameters passed in the opposite direction as the edge.
- * E: Edge -- resolved (negotiated) parameters describing conceptual information on graph edges.
- * B: Bundle should extends from [[chisel3.Data]].
- *
- * {{{
- *
- *
- * Upwards (a.k.a. towards Sources) ↓
- * ↓
- * inward edge of (parameter) type EI ↓
- * created from parameters of type UI and DI ↓
- * will result in a Bundle of type BI ↓
- * ↓
- * ^ ↓ *
- * . ↓ *
- * ┌───────────────────────────────.──↓──*───────────────────────────────┐
- * │ . ↓ * BaseNode │
- * │ . ↓ * (NodeImp) │
- * │ . ↓ * │
- * │ ┌────────────────────────────.──↓──*────────────────────────────┐ │
- * │ │ . ↓ * InwardNode (InwardNodeImp)│ │
- * │ │ (mixI)↓ * │ │
- * │ │ . ↓ * │ │
- * │ │ Upward-flowing inwards . ↓ * Downward-Flowing inwards │ │
- * │ │ parameters of type UI . ↓ * parameters of type DI │ │
- * │ └────────────────────────────.──↓──*────────────────────────────┘ │
- * │ . ↓ * │
- * │ . I v │
- * │ (mapParamsU) (mapParamsD) │
- * │ ^ O + │
- * │ : ↓ + │
- * │ ┌────────────────────────────:──↓──+────────────────────────────┐ │
- * │ │ : ↓ + OutwardNode(OutwardNodeImp)│ │
- * │ │ : ↓ (mixO) │ │
- * │ │ : ↓ + │ │
- * │ │ Upward-flowing outwards : ↓ + Downward-Flowing outward │ │
- * │ │ parameters of type UO : ↓ + parameters of type DO │ │
- * │ └────────────────────────────:──↓──+────────────────────────────┘ │
- * │ : ↓ + │
- * │ : ↓ + │
- * └───────────────────────────────.──↓──*───────────────────────────────┘
- * : ↓ *
- * : ↓ v
- * ↓ outward edge of (parameter) type EO
- * ↓ created from parameters of type UO and DO
- * ↓ will result in a Bundle of type BO
- * ↓
- * ↓ Downwards (a.k.a. towards Sinks)
- *
- * }}}
- *
- * == Handles ==
- *
- * Two Diplomatic nodes can be bound together using the `:=` operator or one of
- * its sibling operators. Binding is asymmetric, and the binding operation will
- * connect the outward of one node to the inward of the other.
- *
- * For example, the expression `a := b` will connect the outward of `b` to the
- * inward of `a`.
- *
- * We would like the `:=` operator to have additional properties that make it
- * intuitive to use:
- *
- * 1. It should be chainable, so that `a := b := c` will have the intuitive effect
- * of binding c to b and b to a. This requires that the return type of `:=` be the
- * same as its arguments, because the result of one `:=` operation must be
- * valid as an argument to other `:=` operations.
- *
- * 2. It should be associative, so that `(a := b) := c` is equivalent to `a := (b := c).`
- * This means that the order in which the bind operations execute does
- * not matter, even if split across multiple files.
- *
- * 3. `a := b` should only be allowed if and only if `b` allows outward edges and `a`
- * allows inward edges. This should be preserved even when chaining
- * operations, and it should ideally be enforced at compile time.
- *
- * [[NodeHandle]] are a way of satisfying all of these properties. A Handle represents
- * the aggregation of a chain of Nodes, and it preserves information about
- * the connectability of the innermost and the outermost sides of the chain.
- *
- * If `b` supports inward edges, then `a := b` returns a [[NodeHandle]] that supports inward
- * edges that go into `b`. If `a` supports outward edges, then `a := b` returns a
- * [[NodeHandle]] that supports outward edges coming out of `a`.
- *
- * ==Node Terms==
- *
- * These are some conventionally used terms for diplomatic Nodes,
- * which describe different common subtypes that certain protocol implementation might utilize:
- * - Mixed: implies that the inward and outward NodeImp are not the same (some sort of protocol conversion is occurring between the two implementations).
- * - Adapter: the number of inward and outward edges must be the same.
- * - Nexus: the number of nodes connecting from either side are unknown until the graph is constructed and can differ from one another.
- * - Identity: modifies neither the parameters nor the protocol-specific circuitry for the edges that pass through it.
- * - Source: cannot have inward edges.
- * - Sink: cannot have outward edges.
- * - Junction: the number of inward and outward edges must have a fixed ratio to one another
- * - Ephemeral: a temporary placeholder used for connectivity operations
+/** Rocketchip Specific Diplomacy code. All other Diplomacy core functionality has been moved to standalone diplomacy
*/
-package object diplomacy
-{
- type SimpleNodeHandle[D, U, E, B <: Data] = NodeHandle[D, U, E, B, D, U, E, B]
- type AnyMixedNode = MixedNode[_, _, _, _ <: Data, _, _, _, _ <: Data]
-
- def sourceLine(sourceInfo: SourceInfo, prefix: String = " (", suffix: String = ")") = sourceInfo match {
- case SourceLine(filename, line, col) => s"$prefix$filename:$line:$col$suffix"
- case _ => ""
- }
-
+package object diplomacy {
def bitIndexes(x: BigInt, tail: Seq[Int] = Nil): Seq[Int] = {
require (x >= 0)
if (x == 0) {
@@ -222,21 +47,230 @@ package object diplomacy
def asProperty: Seq[ResourceValue] = Seq(ResourceReference(x.label))
}
- def EnableMonitors[T](body: Parameters => T)(implicit p: Parameters) = body(p.alterPartial {
- case MonitorsEnabled => true
- })
- def DisableMonitors[T](body: Parameters => T)(implicit p: Parameters) = body(p.alterPartial {
- case MonitorsEnabled => false
- })
- def FlipRendering[T](body: Parameters => T)(implicit p: Parameters) = body(p.alterPartial {
- case RenderFlipped => !p(RenderFlipped)
- })
+ implicit def noCrossing(value: NoCrossing.type): ClockCrossingType = SynchronousCrossing(BufferParams.none)
+
+ // TODO - Remove compatibility layer for deprecated diplomacy api once all local references are moved to standalone diplomacy lib.
+ // package.scala
+ @deprecated("Diplomacy has been split to a standalone library", "rocketchip 2.0.0")
+ def sourceLine(sourceInfo: SourceInfo, prefix: String = " (", suffix: String = ")") = sourceInfo match {
+ case SourceLine(filename, line, col) => s"$prefix$filename:$line:$col$suffix"
+ case _ => ""
+ }
+ @deprecated("Diplomacy has been split to a standalone library", "rocketchip 2.0.0")
+ def EnableMonitors[T](
+ body: Parameters => T
+ )(
+ implicit p: Parameters
+ ) = _root_.org.chipsalliance.diplomacy.EnableMonitors(body)(p)
+ @deprecated("Diplomacy has been split to a standalone library", "rocketchip 2.0.0")
+ def DisableMonitors[T](
+ body: Parameters => T
+ )(
+ implicit p: Parameters
+ ) = _root_.org.chipsalliance.diplomacy.DisableMonitors(body)(p)
+ @deprecated("Diplomacy has been split to a standalone library", "rocketchip 2.0.0")
+ def FlipRendering[T](
+ body: Parameters => T
+ )(
+ implicit p: Parameters
+ ) = _root_.org.chipsalliance.diplomacy.FlipRendering(body)(p)
+ @deprecated("Diplomacy has been split to a standalone library", "rocketchip 2.0.0")
+ implicit def moduleValue[T](value: ModuleValue[T]): T = _root_.org.chipsalliance.diplomacy.moduleValue(value)
- implicit def moduleValue[T](value: ModuleValue[T]): T = value.getWrappedValue
+// Clone.scala
+ @deprecated("Diplomacy has been split to a standalone library", "rocketchip 2.0.0")
+ val CloneLazyModule = _root_.org.chipsalliance.diplomacy.lazymodule.CloneLazyModule
- implicit def noCrossing(value: NoCrossing.type): ClockCrossingType = SynchronousCrossing(BufferParams.none)
+// ValName.scala
+ @deprecated("Diplomacy has been split to a standalone library", "rocketchip 2.0.0")
+ type ValName = _root_.org.chipsalliance.diplomacy.ValName
+ @deprecated("Diplomacy has been split to a standalone library", "rocketchip 2.0.0")
+ def ValName(value: String) = _root_.org.chipsalliance.diplomacy.ValName(value)
+ @deprecated("Diplomacy has been split to a standalone library", "rocketchip 2.0.0")
+ implicit def SourcecodeNameExt(x: sourcecode.Name) = _root_.org.chipsalliance.diplomacy.SourcecodeNameExt(x)
+
+// LazyModule.scala
+ @deprecated("Diplomacy has been split to a standalone library", "rocketchip 2.0.0")
+ type LazyModule = _root_.org.chipsalliance.diplomacy.lazymodule.LazyModule
+ @deprecated("Diplomacy has been split to a standalone library", "rocketchip 2.0.0")
+ val LazyModule = _root_.org.chipsalliance.diplomacy.lazymodule.LazyModule
+ @deprecated("Diplomacy has been split to a standalone library", "rocketchip 2.0.0")
+ type LazyModuleImpLike = _root_.org.chipsalliance.diplomacy.lazymodule.LazyModuleImpLike
+ @deprecated("Diplomacy has been split to a standalone library", "rocketchip 2.0.0")
+ type LazyModuleImp = _root_.org.chipsalliance.diplomacy.lazymodule.LazyModuleImp
+ @deprecated("Diplomacy has been split to a standalone library", "rocketchip 2.0.0")
+ type LazyRawModuleImp = _root_.org.chipsalliance.diplomacy.lazymodule.LazyRawModuleImp
+ @deprecated("Diplomacy has been split to a standalone library", "rocketchip 2.0.0")
+ type SimpleLazyModule = _root_.org.chipsalliance.diplomacy.lazymodule.SimpleLazyModule
+ @deprecated("Diplomacy has been split to a standalone library", "rocketchip 2.0.0")
+ type LazyScope = _root_.org.chipsalliance.diplomacy.lazymodule.LazyScope
+ @deprecated("Diplomacy has been split to a standalone library", "rocketchip 2.0.0")
+ val LazyScope = _root_.org.chipsalliance.diplomacy.lazymodule.LazyScope
+ @deprecated("Diplomacy has been split to a standalone library", "rocketchip 2.0.0")
+ type ModuleValue[T] = _root_.org.chipsalliance.diplomacy.lazymodule.ModuleValue[T]
+ @deprecated("Diplomacy has been split to a standalone library", "rocketchip 2.0.0")
+ val InModuleBody = _root_.org.chipsalliance.diplomacy.lazymodule.InModuleBody
+
+// Nodes.scala
+ @deprecated("Diplomacy has been split to a standalone library", "rocketchip 2.0.0")
+ type Dangle = _root_.org.chipsalliance.diplomacy.nodes.Dangle
+ @deprecated("Diplomacy has been split to a standalone library", "rocketchip 2.0.0")
+ val Dangle = _root_.org.chipsalliance.diplomacy.nodes.Dangle
+ @deprecated("Diplomacy has been split to a standalone library", "rocketchip 2.0.0")
+ type HalfEdge = _root_.org.chipsalliance.diplomacy.nodes.HalfEdge
+ @deprecated("Diplomacy has been split to a standalone library", "rocketchip 2.0.0")
+ val HalfEdge = _root_.org.chipsalliance.diplomacy.nodes.HalfEdge
+ @deprecated("Diplomacy has been split to a standalone library", "rocketchip 2.0.0")
+ val MonitorsEnabled = _root_.org.chipsalliance.diplomacy.nodes.MonitorsEnabled
+ @deprecated("Diplomacy has been split to a standalone library", "rocketchip 2.0.0")
+ val RenderFlipped = _root_.org.chipsalliance.diplomacy.nodes.RenderFlipped
+ @deprecated("Diplomacy has been split to a standalone library", "rocketchip 2.0.0")
+ val RenderedEdge = _root_.org.chipsalliance.diplomacy.nodes.RenderedEdge
+ @deprecated("Diplomacy has been split to a standalone library", "rocketchip 2.0.0")
+ type RenderedEdge = _root_.org.chipsalliance.diplomacy.nodes.RenderedEdge
+ @deprecated("Diplomacy has been split to a standalone library", "rocketchip 2.0.0")
+ type InwardNodeImp[DI, UI, EI, BI <: Data] = _root_.org.chipsalliance.diplomacy.nodes.InwardNodeImp[DI, UI, EI, BI]
+ @deprecated("Diplomacy has been split to a standalone library", "rocketchip 2.0.0")
+ type OutwardNodeImp[DO, UO, EO, BO <: Data] = _root_.org.chipsalliance.diplomacy.nodes.OutwardNodeImp[DO, UO, EO, BO]
+ @deprecated("Diplomacy has been split to a standalone library", "rocketchip 2.0.0")
+ type NodeImp[D, U, EO, EI, B <: Data] = _root_.org.chipsalliance.diplomacy.nodes.NodeImp[D, U, EO, EI, B]
+ @deprecated("Diplomacy has been split to a standalone library", "rocketchip 2.0.0")
+ type SimpleNodeImp[D, U, E, B <: Data] = _root_.org.chipsalliance.diplomacy.nodes.SimpleNodeImp[D, U, E, B]
+ @deprecated("Diplomacy has been split to a standalone library", "rocketchip 2.0.0")
+ type BaseNode = _root_.org.chipsalliance.diplomacy.nodes.BaseNode
+ @deprecated("Diplomacy has been split to a standalone library", "rocketchip 2.0.0")
+ val BaseNode = _root_.org.chipsalliance.diplomacy.nodes.BaseNode
+ @deprecated("Diplomacy has been split to a standalone library", "rocketchip 2.0.0")
+ type FormatEdge = _root_.org.chipsalliance.diplomacy.nodes.FormatEdge
+ @deprecated("Diplomacy has been split to a standalone library", "rocketchip 2.0.0")
+ type FormatNode[I <: FormatEdge, O <: FormatEdge] = _root_.org.chipsalliance.diplomacy.nodes.FormatNode[I, O]
+ @deprecated("Diplomacy has been split to a standalone library", "rocketchip 2.0.0")
+ type NoHandle = _root_.org.chipsalliance.diplomacy.nodes.NoHandle
+ @deprecated("Diplomacy has been split to a standalone library", "rocketchip 2.0.0")
+ val NoHandleObject = _root_.org.chipsalliance.diplomacy.nodes.NoHandleObject
+ @deprecated("Diplomacy has been split to a standalone library", "rocketchip 2.0.0")
+ type NodeHandle[DI, UI, EI, BI <: Data, DO, UO, EO, BO <: Data] =
+ _root_.org.chipsalliance.diplomacy.nodes.NodeHandle[DI, UI, EI, BI, DO, UO, EO, BO]
+ @deprecated("Diplomacy has been split to a standalone library", "rocketchip 2.0.0")
+ val NodeHandle = _root_.org.chipsalliance.diplomacy.nodes.NodeHandle
+ @deprecated("Diplomacy has been split to a standalone library", "rocketchip 2.0.0")
+ type NodeHandlePair[DI, UI, EI, BI <: Data, DO, UO, EO, BO <: Data] =
+ _root_.org.chipsalliance.diplomacy.nodes.NodeHandlePair[DI, UI, EI, BI, DO, UO, EO, BO]
+ @deprecated("Diplomacy has been split to a standalone library", "rocketchip 2.0.0")
+ type InwardNodeHandle[DI, UI, EI, BI <: Data] =
+ _root_.org.chipsalliance.diplomacy.nodes.InwardNodeHandle[DI, UI, EI, BI]
+ @deprecated("Diplomacy has been split to a standalone library", "rocketchip 2.0.0")
+ type NodeBinding = _root_.org.chipsalliance.diplomacy.nodes.NodeBinding
+ @deprecated("Diplomacy has been split to a standalone library", "rocketchip 2.0.0")
+ val BIND_ONCE = _root_.org.chipsalliance.diplomacy.nodes.BIND_ONCE
+ @deprecated("Diplomacy has been split to a standalone library", "rocketchip 2.0.0")
+ val BIND_QUERY = _root_.org.chipsalliance.diplomacy.nodes.BIND_QUERY
+ @deprecated("Diplomacy has been split to a standalone library", "rocketchip 2.0.0")
+ val BIND_STAR = _root_.org.chipsalliance.diplomacy.nodes.BIND_STAR
+ @deprecated("Diplomacy has been split to a standalone library", "rocketchip 2.0.0")
+ val BIND_FLEX = _root_.org.chipsalliance.diplomacy.nodes.BIND_FLEX
+ @deprecated("Diplomacy has been split to a standalone library", "rocketchip 2.0.0")
+ type InwardNode[DI, UI, BI <: Data] = _root_.org.chipsalliance.diplomacy.nodes.InwardNode[DI, UI, BI]
+ @deprecated("Diplomacy has been split to a standalone library", "rocketchip 2.0.0")
+ type OutwardNodeHandle[DO, UO, EO, BO <: Data] =
+ _root_.org.chipsalliance.diplomacy.nodes.OutwardNodeHandle[DO, UO, EO, BO]
+ @deprecated("Diplomacy has been split to a standalone library", "rocketchip 2.0.0")
+ type OutwardNode[DO, UO, BO <: Data] = _root_.org.chipsalliance.diplomacy.nodes.OutwardNode[DO, UO, BO]
+ @deprecated("Diplomacy has been split to a standalone library", "rocketchip 2.0.0")
+ type CycleException = _root_.org.chipsalliance.diplomacy.nodes.CycleException
+ @deprecated("Diplomacy has been split to a standalone library", "rocketchip 2.0.0")
+ type StarCycleException = _root_.org.chipsalliance.diplomacy.nodes.StarCycleException
+ @deprecated("Diplomacy has been split to a standalone library", "rocketchip 2.0.0")
+ type DownwardCycleException = _root_.org.chipsalliance.diplomacy.nodes.DownwardCycleException
+ @deprecated("Diplomacy has been split to a standalone library", "rocketchip 2.0.0")
+ type UpwardCycleException = _root_.org.chipsalliance.diplomacy.nodes.UpwardCycleException
+ @deprecated("Diplomacy has been split to a standalone library", "rocketchip 2.0.0")
+ val Edges = _root_.org.chipsalliance.diplomacy.nodes.Edges
+ @deprecated("Diplomacy has been split to a standalone library", "rocketchip 2.0.0")
+ type Edges[EI, EO] = _root_.org.chipsalliance.diplomacy.nodes.Edges[EI, EO]
+ @deprecated("Diplomacy has been split to a standalone library", "rocketchip 2.0.0")
+ type MixedCustomNode[DI, UI, EI, BI <: Data, DO, UO, EO, BO <: Data] =
+ _root_.org.chipsalliance.diplomacy.nodes.MixedCustomNode[DI, UI, EI, BI, DO, UO, EO, BO]
+ @deprecated("Diplomacy has been split to a standalone library", "rocketchip 2.0.0")
+ type CustomNode[D, U, EO, EI, B <: Data] = _root_.org.chipsalliance.diplomacy.nodes.CustomNode[D, U, EO, EI, B]
+ @deprecated("Diplomacy has been split to a standalone library", "rocketchip 2.0.0")
+ type MixedJunctionNode[DI, UI, EI, BI <: Data, DO, UO, EO, BO <: Data] =
+ _root_.org.chipsalliance.diplomacy.nodes.MixedJunctionNode[DI, UI, EI, BI, DO, UO, EO, BO]
+ @deprecated("Diplomacy has been split to a standalone library", "rocketchip 2.0.0")
+ type JunctionNode[D, U, EO, EI, B <: Data] = _root_.org.chipsalliance.diplomacy.nodes.JunctionNode[D, U, EO, EI, B]
+ @deprecated("Diplomacy has been split to a standalone library", "rocketchip 2.0.0")
+ type MixedAdapterNode[DI, UI, EI, BI <: Data, DO, UO, EO, BO <: Data] =
+ _root_.org.chipsalliance.diplomacy.nodes.MixedAdapterNode[DI, UI, EI, BI, DO, UO, EO, BO]
+ @deprecated("Diplomacy has been split to a standalone library", "rocketchip 2.0.0")
+ type AdapterNode[D, U, EO, EI, B <: Data] = _root_.org.chipsalliance.diplomacy.nodes.AdapterNode[D, U, EO, EI, B]
+ @deprecated("Diplomacy has been split to a standalone library", "rocketchip 2.0.0")
+ type IdentityNode[D, U, EO, EI, B <: Data] = _root_.org.chipsalliance.diplomacy.nodes.IdentityNode[D, U, EO, EI, B]
+ @deprecated("Diplomacy has been split to a standalone library", "rocketchip 2.0.0")
+ type EphemeralNode[D, U, EO, EI, B <: Data] = _root_.org.chipsalliance.diplomacy.nodes.EphemeralNode[D, U, EO, EI, B]
+ @deprecated("Diplomacy has been split to a standalone library", "rocketchip 2.0.0")
+ type MixedNexusNode[DI, UI, EI, BI <: Data, DO, UO, EO, BO <: Data] =
+ _root_.org.chipsalliance.diplomacy.nodes.MixedNexusNode[DI, UI, EI, BI, DO, UO, EO, BO]
+ @deprecated("Diplomacy has been split to a standalone library", "rocketchip 2.0.0")
+ type NexusNode[D, U, EO, EI, B <: Data] = _root_.org.chipsalliance.diplomacy.nodes.NexusNode[D, U, EO, EI, B]
+ @deprecated("Diplomacy has been split to a standalone library", "rocketchip 2.0.0")
+ type SourceNode[D, U, EO, EI, B <: Data] = _root_.org.chipsalliance.diplomacy.nodes.SourceNode[D, U, EO, EI, B]
+ @deprecated("Diplomacy has been split to a standalone library", "rocketchip 2.0.0")
+ type SinkNode[D, U, EO, EI, B <: Data] = _root_.org.chipsalliance.diplomacy.nodes.SinkNode[D, U, EO, EI, B]
+ @deprecated("Diplomacy has been split to a standalone library", "rocketchip 2.0.0")
+ type SimpleNodeHandle[D, U, E, B <: Data] = _root_.org.chipsalliance.diplomacy.nodes.SimpleNodeHandle[D, U, E, B]
+ @deprecated("Diplomacy has been split to a standalone library", "rocketchip 2.0.0")
+ type AnyMixedNode = _root_.org.chipsalliance.diplomacy.nodes.AnyMixedNode
- type BundleBridgeInwardNode[T <: Data] = InwardNodeHandle[BundleBridgeParams[T], BundleBridgeParams[T], BundleBridgeEdgeParams[T], T]
- type BundleBridgeOutwardNode[T <: Data] = OutwardNodeHandle[BundleBridgeParams[T], BundleBridgeParams[T], BundleBridgeEdgeParams[T], T]
- type BundleBridgeNode[T <: Data] = NodeHandle[BundleBridgeParams[T], BundleBridgeParams[T], BundleBridgeEdgeParams[T], T, BundleBridgeParams[T], BundleBridgeParams[T], BundleBridgeEdgeParams[T], T]
+// BundleBridge.scala
+ @deprecated("Diplomacy has been split to a standalone library", "rocketchip 2.0.0")
+ type BundleBridgeParams[T <: Data] = _root_.org.chipsalliance.diplomacy.bundlebridge.BundleBridgeParams[T]
+ @deprecated("Diplomacy has been split to a standalone library", "rocketchip 2.0.0")
+ val BundleBridgeParams = _root_.org.chipsalliance.diplomacy.bundlebridge.BundleBridgeParams
+ @deprecated("Diplomacy has been split to a standalone library", "rocketchip 2.0.0")
+ type BundleBridgeEdgeParams[T <: Data] = _root_.org.chipsalliance.diplomacy.bundlebridge.BundleBridgeEdgeParams[T]
+ @deprecated("Diplomacy has been split to a standalone library", "rocketchip 2.0.0")
+ type BundleBridgeImp[T <: Data] = _root_.org.chipsalliance.diplomacy.bundlebridge.BundleBridgeImp[T]
+ @deprecated("Diplomacy has been split to a standalone library", "rocketchip 2.0.0")
+ type BundleBridgeSink[T <: Data] = _root_.org.chipsalliance.diplomacy.bundlebridge.BundleBridgeSink[T]
+ @deprecated("Diplomacy has been split to a standalone library", "rocketchip 2.0.0")
+ val BundleBridgeSink = _root_.org.chipsalliance.diplomacy.bundlebridge.BundleBridgeSink
+ @deprecated("Diplomacy has been split to a standalone library", "rocketchip 2.0.0")
+ type BundleBridgeSource[T <: Data] = _root_.org.chipsalliance.diplomacy.bundlebridge.BundleBridgeSource[T]
+ @deprecated("Diplomacy has been split to a standalone library", "rocketchip 2.0.0")
+ val BundleBridgeSource = _root_.org.chipsalliance.diplomacy.bundlebridge.BundleBridgeSource
+ @deprecated("Diplomacy has been split to a standalone library", "rocketchip 2.0.0")
+ type BundleBridgeIdentityNode[T <: Data] = _root_.org.chipsalliance.diplomacy.bundlebridge.BundleBridgeIdentityNode[T]
+ @deprecated("Diplomacy has been split to a standalone library", "rocketchip 2.0.0")
+ val BundleBridgeIdentityNode = _root_.org.chipsalliance.diplomacy.bundlebridge.BundleBridgeIdentityNode
+ @deprecated("Diplomacy has been split to a standalone library", "rocketchip 2.0.0")
+ type BundleBridgeEphemeralNode[T <: Data] =
+ _root_.org.chipsalliance.diplomacy.bundlebridge.BundleBridgeEphemeralNode[T]
+ @deprecated("Diplomacy has been split to a standalone library", "rocketchip 2.0.0")
+ val BundleBridgeEphemeralNode = _root_.org.chipsalliance.diplomacy.bundlebridge.BundleBridgeEphemeralNode
+ @deprecated("Diplomacy has been split to a standalone library", "rocketchip 2.0.0")
+ def BundleBridgeNameNode[T <: Data](name: String) =
+ _root_.org.chipsalliance.diplomacy.bundlebridge.BundleBridgeNameNode[T](name)
+ @deprecated("Diplomacy has been split to a standalone library", "rocketchip 2.0.0")
+ type BundleBridgeNexusNode[T <: Data] = _root_.org.chipsalliance.diplomacy.bundlebridge.BundleBridgeNexusNode[T]
+ @deprecated("Diplomacy has been split to a standalone library", "rocketchip 2.0.0")
+ type BundleBridgeNexus[T <: Data] = _root_.org.chipsalliance.diplomacy.bundlebridge.BundleBridgeNexus[T]
+ @deprecated("Diplomacy has been split to a standalone library", "rocketchip 2.0.0")
+ val BundleBridgeNexus = _root_.org.chipsalliance.diplomacy.bundlebridge.BundleBridgeNexus
+ @deprecated("Diplomacy has been split to a standalone library", "rocketchip 2.0.0")
+ def BundleBroadcast[T <: Data](
+ name: Option[String] = None,
+ registered: Boolean = false,
+ default: Option[() => T] = None,
+ inputRequiresOutput: Boolean = false, // when false, connecting a source does not mandate connecting a sink
+ shouldBeInlined: Boolean = true
+ )(
+ implicit p: Parameters
+ ) = _root_.org.chipsalliance.diplomacy.bundlebridge
+ .BundleBroadcast[T](name, registered, default, inputRequiresOutput, shouldBeInlined)(p)
+ @deprecated("Diplomacy has been split to a standalone library", "rocketchip 2.0.0")
+ type BundleBridgeInwardNode[T <: Data] = _root_.org.chipsalliance.diplomacy.bundlebridge.BundleBridgeInwardNode[T]
+ @deprecated("Diplomacy has been split to a standalone library", "rocketchip 2.0.0")
+ type BundleBridgeOutwardNode[T <: Data] = _root_.org.chipsalliance.diplomacy.bundlebridge.BundleBridgeOutwardNode[T]
+ @deprecated("Diplomacy has been split to a standalone library", "rocketchip 2.0.0")
+ type BundleBridgeNode[T <: Data] = _root_.org.chipsalliance.diplomacy.bundlebridge.BundleBridgeNode[T]
}
diff --git a/src/main/scala/util/HeterogeneousBag.scala b/src/main/scala/util/HeterogeneousBag.scala
deleted file mode 100644
index f9a591b4b4..0000000000
--- a/src/main/scala/util/HeterogeneousBag.scala
+++ /dev/null
@@ -1,24 +0,0 @@
-// See LICENSE.SiFive for license details.
-
-package freechips.rocketchip.util
-
-import chisel3._
-import chisel3.Record
-import chisel3.reflect.DataMirror.internal.chiselTypeClone
-import scala.collection.immutable.ListMap
-
-final case class HeterogeneousBag[T <: Data](elts: Seq[T]) extends Record with collection.IndexedSeq[T] {
- def apply(x: Int) = elements(x.toString).asInstanceOf[T]
- def length = elts.length
-
- override def className: String = super.className
- val elements = ListMap(elts.zipWithIndex.map { case (n,i) => (i.toString, chiselTypeClone(n)) }:_*)
- // IndexedSeq has its own hashCode/equals that we must not use
- override def hashCode: Int = super[Record].hashCode
- override def equals(that: Any): Boolean = super[Record].equals(that)
-}
-
-object HeterogeneousBag
-{
- def fromNode[D <: Data, E](elts: Seq[(D, E)]) = new HeterogeneousBag(elts.map(_._1.cloneType))
-}
diff --git a/src/main/scala/util/package.scala b/src/main/scala/util/package.scala
index bacaf5b7b1..43eddcb236 100644
--- a/src/main/scala/util/package.scala
+++ b/src/main/scala/util/package.scala
@@ -286,4 +286,10 @@ package object util {
case x if x == n => in
case _ => throw new Exception(s"must provide exactly 1 or $n of some field, but got:\n$in")
}
+
+ // HeterogeneousBag moved to standalond diplomacy
+ @deprecated("HeterogeneousBag has been absorbed into standalone diplomacy library", "rocketchip 2.0.0")
+ def HeterogeneousBag[T <: Data](elts: Seq[T]) = _root_.org.chipsalliance.diplomacy.nodes.HeterogeneousBag[T](elts)
+ @deprecated("HeterogeneousBag has been absorbed into standalone diplomacy library", "rocketchip 2.0.0")
+ val HeterogeneousBag = _root_.org.chipsalliance.diplomacy.nodes.HeterogeneousBag
}