scala - 如何理解autobundle()和makeios中的翻转?
问题描述
在 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
}
}
解决方案
这是一段相当复杂的代码(外交/LazyModule 是一个非常先进的生成器),但.flip
它是 Chisel 3 中的 Chisel 2 API 等效项Flipped(...)
。它通过 Chisel 2 兼容层用于火箭芯片(import Chisel._
相反到import chisel3._
)。
Flipped
反转类型的方向。请注意,这是递归的,并且类型可以是双向的(通常在Flipped
使用时)。
例如:
class Example extends MultiIOModule {
// .valid and .bits are inputs, .ready is an output
val in = IO(Flipped(Decoupled(UInt(8.W))))
// .valid and .bits are outputs, .ready is an input
val out = IO(Decoupled(UInt(8.W)))
out <> in
}
(Scastie 链接:https ://scastie.scala-lang.org/F91trxakSFSrlVrzk3VxcA )
基本上,当使用现成有效的接口时,您经常需要“翻转”生产者或消费者接口中的方向。
推荐阅读
- python - 分组和组合字符串
- node.js - electron-forge:缺少依赖项 = git 和节点,但我可以选择哪个 git?
- c# - 如何将用户选择的值存储到由 SharePoint Web 部件呈现的 n DropDown 中?
- r - nnfor 包中的 elm 函数无法识别 xreg 的输入
- sql - 在 T-SQL 中将 24 小时分成 96 个相等的 15 分钟间隔
- node.js - 如何在 NodeJS/Express 中验证 base64 图像?
- regex - 正则表达式在第 4 次出现后查找
- android - 如何在 React Native 中的启动画面后禁用后退按钮
- java - 可变字段不应该是“公共静态的”
- javascript - 使用javascript以特定顺序对具有十进制值的数组进行排序