LazyModule 和 LazyModuleImp 之间的差异

Differences between LazyModule and LazyModuleImp

LazyModule 和 LazyModuleImp 有什么区别? 就像rocket-chip/doc下的外交演示说的那样:The desired hardware for the module must be written inside LazyModuleImp. 但考虑以下代码:

class A(implicit p: Parameters) extends LazyModule {
  val b = LazyModule(new Leaf)
  val c = LazyModule(new Leaf)

  val input = b.input
  val output = c.output

  val bOutput = b.output.makeSink
  val cInput = BundleBridgeSource[Bool](() => Bool())
  c.input := cInput
  lazy val module = new LazyModuleImp(this) {
    cInput.bundle := bOutput.bundle
  }
}

:=是硬件操作,在LazyModuleImp内部和外部都会出现,那么LazyModuleImp应该放哪段代码?

考虑 LazyModule 的最佳方式 (IMO) 是 LazyModule 本质上有两个部分

  1. 非硬件实现(LazyModuleImp 之外的所有内容)这是我们定义 Nodes、解析参数、执行任何人们认为是“软件”的地方
  2. 硬件实现(LazyModuleImp 中的所有内容)这是我们创建实际硬件的地方。我们一般都是用外面解析出来的参数来搭建一些硬件。

在外交方面,:=实际上是Node联系。您在其中连接两个外交节点。执行此连接时,您实际上是在“绘制”从一个节点到另一个节点的路径。在外交演示的情况下,您将把 AdderDriverNode 连接到 AdderNode。这是在 LazyModuleImp 外部 执行的,因为我们需要在 之前定义此节点图 我们可以构建硬件。

例如,如果您查看 AdderTestHarness,您可以在 LazyModuleImp

之外看到以下内容
  // create edges via binding operators between nodes in order to define a complete graph
  drivers.foreach{ driver => adder.node := driver.node }

  drivers.zip(monitor.nodeSeq).foreach { case (driver, monitorNode) => monitorNode := driver.node }
  monitor.nodeSum := adder.node

在这里,我们将驱动程序连接到加法器,将驱动程序连接到监视器,然后将加法器连接到监视器。这些连接基于为每个节点定义的 Bundle 生成创建硬件。

所以我倾向于将 LazyModules 和一般的外交视为创建硬件的两次通过方法。第一步是定义硬件拓扑。这是在 LazyModuleImp 之外完成的。我将描述每一块是如何连接的,并解析宽度、地址等参数。第二遍是实际的硬件生成。在这里,我所有的参数都应该被解析,我定义的硬件现在已经创建了。

外交令人印象深刻,但掌握起来却相当困难。特别是如果来自严格的硬件背景或严格的软件背景。它需要对某些软件范例的工作原理有深刻的理解,才能掌握 parameter/edge 分辨率的架构,然后你就会遇到使用它来实际创建一些真实硬件的障碍。