FPGA開発日記

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

Diplomacyを使ってOCPバスを作成する(12. Xbarの作成を行う)

Diplomacyを使ったOCPプロトコルの作成、次にXbarの作成を行う。Xbarというのはクロスバで、複数のマスターとスレーブを接続する。まずは1マスターから複数スレーブに向けて接続する回路を作成する。

Diplomacyのクロスバの考え方はこうだ。まずはすべてのマスターからのリクエストを集約し、Arbiterに接続する。

  • chisel-hw/src/main/scala/ocp/Xbar.scala
val in = Wire(Vec(io_in.size, OCPBundle(wide_bundle)))
for (i <- 0 until in.size) {
  val r = inputIdRanges(i)

  in(i).cmd <> io_in(i).cmd
  in(i).cmd.bits.tagId := io_in(i).cmd.bits.tagId | UInt(r.start)

  in(i).data <> io_in(i).data
  in(i).data.bits.tagId := io_in(i).data.bits.tagId | UInt(r.start)

  io_in(i).resp <> in(i).resp
}

これらのin配列に入った信号をどのように処理するのか。以下のようにしてアウトプット毎にArbiterを配置してソースを選択する論理を入れる。

// Arbitrate amongst the sources
for (o <- 0 until out.size) {
  OCPArbiter(policy, out(o).cmd,  filter(beatsCmdI  zip portsCmdOI(o),  connectAOI(o)):_*)
  OCPArbiter(policy, out(o).data, filter(beatsDataI zip portsDataOI(o), connectCOI(o)):_*)
}

一方で戻り側はどうするか。これと逆方向に接続する。

for (i <- 0 until in.size) {
  OCPArbiter(policy, in(i).resp, filter(beatsRespO zip portsRespIO(i), connectDIO(i)):_*)
}
// Transform output bundle sinks (sources use global namespace on both sides)
val out = Wire(Vec(io_out.size, OCPBundle(wide_bundle)))
for (o <- 0 until out.size) {
  val r = outputIdRanges(o)

  io_out(o).cmd <> out(o).cmd

  io_out(o).data <> out(o).data

  out(o).resp <> io_out(o).resp
  out(o).resp.bits.tagId := io_out(o).resp.bits.tagId | UInt(r.start)
}

さて、テストを行う。以下のようなテストコードを作成した。

class OCPUnitXbar()(implicit p: Parameters) extends LazyModule {
  val pusher1 = LazyModule(new OCPPatternPusher("pat1", Seq(
    new WriteReqPattern   (0, 0x100, 0x2),
    new WriteDataPattern  (0, 0x012345678L),
...
  )))
  val ram0 = LazyModule(new OCPRAM(AddressSet(0x000, 0x3ff)))
  val ram1 = LazyModule(new OCPRAM(AddressSet(0x400, 0x3ff)))
  val xbar = LazyModule(new OCPXbar())

  xbar.node := pusher1.node
  ram0.node := xbar.node
  ram1.node := xbar.node

  lazy val module = new LazyModuleImp(this) with UnitTestModule {
    pusher1.module.io.run := true.B
    io.finished := pusher1.module.io.done
  }
}

GraphMLを作成する。Pusher1が1つのマスターで、ram0とram1がスレーブとなっている。

f:id:msyksphinz:20200303001445p:plain

一応、正しく動作しているようだ。

$ make tilelink CONFIG=OCPUnitXbarTestConfig
Started UnitTest OCPUnitXbarTest
Resp Fired : same as expected. 12345678
Resp Fired : same as expected. abcdef01
Resp Fired : same as expected. deadbeef
Resp Fired : same as expected. 87654321