FPGA開発日記

カテゴリ別記事インデックス https://msyksphinz.github.io/github_pages , English Version https://fpgadevdiary.hatenadiary.com/

Diplomacyを使ってOCPバスを作成する(14. Xbarの理解)

DiplomacyのXbarについて理解を深めるためにソースコードを読んでみよう。とりまOCPの実装をしたいのだが、何せ内部を理解しないとどうも改造できそうにない気がしてきた。どうにかしてソースコードを理解しなければ。

NexusNodeについて

NexusNodeは複数のSlaveと複数のMasterを接続することのできるノードだ。接続中に、ノードの信号情報を変更することもできる。

f:id:msyksphinz:20200305001925p:plain
  val node = TLNexusNode(
    clientFn  = { seq =>
      seq(0).copy(
        minLatency = seq.map(_.minLatency).min,
        clients = (TLXbar.mapInputIds(seq) zip seq) flatMap { case (range, port) =>
          port.clients map { client => client.copy(
            sourceId = client.sourceId.shift(range.start)
          )}
        }
      )
    },
    managerFn = { seq =>
      val fifoIdFactory = TLXbar.relabeler()
      seq(0).copy(
        minLatency = seq.map(_.minLatency).min,
        endSinkId = TLXbar.mapOutputIds(seq).map(_.end).max,
        managers = seq.flatMap { port =>
          require (port.beatBytes == seq(0).beatBytes,
            s"Xbar data widths don't match: ${port.managers.map(_.name)} has ${port.beatBytes}B vs ${seq(0).managers.map(_.name)} has ${seq(0).beatBytes}B")
          val fifoIdMapper = fifoIdFactory()
          port.managers map { manager => manager.copy(
            fifoId = manager.fifoId.map(fifoIdMapper(_))
          )}
        }
      )
    })

The clientFn is a function that takes the TLClientPortParameters of the input as an argument and returns the corresponding parameters for the output. The managerFn takes the TLManagerPortParameters of the output as an argument and returns the corresponding parameters for the input.

clientFnTLClientPortParameterを引数に取る関数で、出力に対して相当するパラメータを返す。

managerFnTLManagerPortParametersを引数に取る関数で、入力に対して相当するパラメータを返す。

例えば、2つのMasterを接続した場合には以下のようにsourceIdが設定された。

sourceId = IdRange(1,2)
sourceId = IdRange(0,1)

次に、requestAIOについて調べていく。Xbarには、リクエストがどのターゲットに対してリクエストを発行しているのかを示すrequestAIOなどという信号が定義されている。

    val requestAIO = (connectAIO zip addressA) map { case (c, i) => outputPortFns(c).map { o => unique(c) || o(i) } }
    val requestCIO = (connectCIO zip addressC) map { case (c, i) => outputPortFns(c).map { o => unique(c) || o(i) } }
    val requestBOI = out.map { o => inputIdRanges.map  { i => i.contains(o.b.bits.source) } }
    val requestDOI = out.map { o => inputIdRanges.map  { i => i.contains(o.d.bits.source) } }
    val requestEIO = in.map  { i => outputIdRanges.map { o => o.contains(i.e.bits.sink) } }

requestAIOは、縦方向がマスター側、横方向がスレーブ側となる。これはリクエストの発行状況を示しているのか?

                  slave
                ~~~~~~~~~
requestAIO[0] = 1,1,1,1,1, |
requestAIO[1] = 1,1,1,1,1, |
requestAIO[2] = 1,1,1,1,1, | masters
requestAIO[3] = 1,1,1,1,1, |

requestDOIは、逆に縦方向がスレーブ側、横方向がマスター側となる。これはレスポンスの発行状況を示しているのか?

                 master
               ~~~~~~~~
requestDOI[0] = 1,0,0,0, |
requestDOI[1] = 0,0,0,1, |
requestDOI[2] = 0,0,0,1, | slave
requestDOI[3] = 0,0,0,1, |
requestDOI[4] = 0,0,0,1, |