4

我在RocketChip中看到了一些示例,但在API 参考中找不到信息

  masterNode :=* tlOtherMastersNode
  DisableMonitors { implicit p => tlSlaveXbar.node :*= slaveNode }
4

3 回答 3

3

这些不是凿子操作员。相反,它们是由 Rocket Chip 的diplomacy包定义和使用的。这些是在外交节点之间进行不同类型绑定的简写运算符。

diplomacy不存在已发布的 API 文档,但您可以开始在包中四处寻找。定义这些的相关位置是src/main/scala/diplomacy/Nodes.scala

于 2018-11-10T20:51:30.967 回答
1

这个 API的拉取请求评论非常有用。

通常,A := B在 A 和 B 中创建一对主从端口。 A :=* B意味着端口对的数量由数量决定B := OtherA :*= B反之亦然。

最反直觉的部分是链路的复制不是通过中间模块的复制来实现的,而是中间模块对端口列表的扩展。

我写了一个简单的例子来探索星形连接器的行为。

在下面的代码片段中,一个 TLIdentifyNode 使用 连接 3 个 TLClientNode :=,然后它连接到一个使用:=*作为 master 到 crossbar 的 crossbar 节点。同时,一个 TLIdentifyNode 使用 连接 2 个 TLManagerNode :=,然后它连接到同一个 crossbar 节点,:*=用作从交叉开关。

import chisel3._
import chisel3.core.dontTouch
import freechips.rocketchip.config._
import freechips.rocketchip.diplomacy._
import freechips.rocketchip.tilelink._


class ClientConnector(implicit p: Parameters) extends LazyModule {
  val node = TLIdentityNode()
  override lazy val module = new LazyModuleImp(this) {
    (node.in zip node.out) foreach { case ((bundleIn, edgeIn), (bundleOut, edgeOut)) =>
      bundleOut <> bundleIn
    }
  }
}


class ManagerConnector(implicit p: Parameters) extends LazyModule {
  val node = TLIdentityNode()
  override lazy val module = new LazyModuleImp(this) {
    (node.in zip node.out) foreach { case ((bundleIn, edgeIn), (bundleOut, edgeOut)) =>
      bundleOut <> bundleIn
    }
  }
}



class Client(implicit p: Parameters) extends LazyModule {
  val node = TLClientNode(
    portParams = Seq(
      TLClientPortParameters(Seq(
        TLClientParameters("myclient1", IdRange(0, 1), supportsGet = TransferSizes(4), supportsProbe = TransferSizes(4))
      ))
    )
  )

  override lazy val module = new LazyModuleImp(this) {
    node.out.foreach { case(bundle, edge) =>
        val (legal, a) = edge.Get(0.U, 0x1000.U, 2.U)
        bundle.a.bits := a
        bundle.a.valid := legal

        bundle.d.ready := true.B

        dontTouch(bundle)
    }
  }
}


class Manager(base: Int)(implicit p: Parameters) extends LazyModule {
  val node = TLManagerNode(Seq(TLManagerPortParameters(Seq(TLManagerParameters(
    address = Seq(AddressSet(base, 0xffff)),
    supportsGet = TransferSizes(4)
  )), beatBytes = 4)))

  override lazy val module = new LazyModuleImp(this) {
    node.in.foreach { case (bundle, edge) =>
        when (bundle.a.fire()) {
          val d = edge.AccessAck(bundle.a.bits, 0xdeadbeafL.U)
          bundle.d.bits := d
          bundle.d.valid := true.B
        }
        bundle.a.ready := true.B
    }
  }
}


class Playground(implicit p: Parameters) extends LazyModule {

  val xbr               = TLXbar()
  val clientConnectors  = LazyModule(new ClientConnector())
  val managerConnectors = LazyModule(new ManagerConnector())
  val clients           = Seq.fill(3) { LazyModule(new Client()).node }
  val managers          = Seq.tabulate(2) { i: Int => LazyModule(new Manager(0x10000 * i)).node }

  clients.foreach(clientConnectors.node := _)
  managers.foreach(_ := managerConnectors.node)

  managerConnectors.node :*= xbr
  xbr :=* clientConnectors.node

  override lazy val module = new LazyModuleImp(this) {
  }
}

对应的verilog代码ManagerConnector为(简言之):

module ManagerConnector(
  `tilelink_bundle(auto_in_0),
  `tilelink_bundle(auto_in_1),
  `tilelink_bundle(auto_out_0),
  `tilelink_bundle(auto_out_1)
);
// ...
endmodule

我们可以看到diplomacy框架只负责参数协商、端口列表生成和端口连接。由连接引入的重复由*通用代码模式保证:

(node.in zip node.out) foreach { ... }

在我看来,这个 API 简化了 crossbar 节点与特定模块内的各个节点之间的连接,并保持连接语法一致。

【参考】一个rocketchip读书笔记:https ://github.com/cnrv/rocket-chip-read/blob/master/diplomacy/Nodes.md

于 2019-09-04T04:37:56.697 回答
0

阅读 lowrisc 的外交文档可能会很有用:https ://www.lowrisc.org/docs/diplomacy/

于 2018-11-15T17:31:04.690 回答