Что означают операторы:*= и:=*?
Я вижу некоторые примеры в RocketChip, но не могу найти информацию в справочнике по API
masterNode :=* tlOtherMastersNode
DisableMonitors { implicit p => tlSlaveXbar.node :*= slaveNode }
2 ответа
Это не долотные операторы. Вместо этого они определены и используются Rocket Chip's diplomacy
пакет. Это сокращенные операторы для выполнения различных типов привязки между дипломатическими узлами.
Опубликованной документации по API для этого не существует, но вы можете начать поискать в diplomacy
пакет. Соответствующее место, где они определены, src/main/scala/diplomacy/Nodes.scala
,
Запрос тянуть комментарий по этому API очень infomative.
Обычно A := B
создает пару главного и подчиненного портов в A и B.A :=* B
означает, что количество пар портов определяется количеством B := Other
, а также A :*= B
наоборот.
Самая нелогичная часть состоит в том, что дублирование ссылок достигается не дублированием промежуточного модуля, а расширением списка портов промежуточным модулем.
Я написал простой пример для изучения поведения звездообразных соединителей.
В следующем фрагменте кода TLIdentifyNode соединяет 3 TLClientNode, используя :=
, а затем он подключается к узлу перекладины с помощью :=*
как мастер на перекладине. Между тем, TLIdentifyNode соединяет 2 TLManagerNode, используя:=
, а затем он подключается к тому же узлу перекладины с помощью :*=
как мазь для перекладины.
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
framework отвечает только за согласование параметров, создание списка портов и подключение портов. Дублирование введено*
соединение гарантируется общим шаблоном кода:
(node.in zip node.out) foreach { ... }
На мой взгляд, этот API упрощает соединение между перекрестным узлом и различными узлами внутри определенного модуля и поддерживает согласованный синтаксис соединения.
[Ссылка] Заметка для чтения ракетного чипа: https://github.com/cnrv/rocket-chip-read/blob/master/diplomacy/Nodes.md
Может быть полезно прочитать документацию по дипломатии по lowrisc: https://www.lowrisc.org/docs/diplomacy/