在 LazyModule.scala 中,函数 AutoBundle() 用 flipped = true 翻转 dangleIn 中的 Data(bundleIn) 以生成 autoIO,而在 Nodes.scala 中,类 sourceNode 中的函数 makeIOs() 翻转 bundleOut 以生成 IO,为什么它们不同?
LazyModule.scala 中的 AutoBundle() 代码:
/** [[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: ListMap[String, Data] = ListMap() ++ 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) data.cloneType.flip() else data.cloneType
(regex.replaceAllIn(key, ""), element, i)
}
override def cloneType: this.type = new AutoBundle(elts: _*).asInstanceOf[this.type]
}
Nodes.scala 中的 makeIOs() 代码:
/** 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.map(_.cloneType))))
ios.suggestName(valName.name)
bundles.zip(ios).foreach { case (bundle, io) => bundle <> io }
ios
}
}