FPGA開発日記

FPGAというより、コンピュータアーキテクチャかもね! カテゴリ別記事インデックス https://msyksphinz.github.io/github_pages

Rocket-Chip実装のリグレッションスイートを試す(2. TL2APB実装の解析)

f:id:msyksphinz:20181008145947p:plain

APBのChisel実装を観察してみる。

今回読んだのは、TL2APBというChiselで書かれた実装だ。TL(TileLink)からAMBAに変換するモジュールについては、

  • ToAPB
  • ToAHB
  • ToAXI4

の3種類があり、まずは一番簡単そうなAPBを観察する。

ちなみにSiFiveが以下のような資料を出していたが、あまり内容は濃くない。インタフェースだけの解説だ。

  • SiFive TileLink To APB Bridge (TL2APB)

https://static.dev.sifive.com/pdfjs/web/viewer.html?file=https://static.dev.sifive.com/TL2APB.pdf

TileLinkをAPBに変換するコードは以下のようになっている。

github.com

TLのリクエストを受け付けるためのQueueが実装されている。

      // We need an irrevocable input for APB to stall
      val a = Queue(in.a, 1, flow = aFlow, pipe = !aFlow)

TLがRead Responseを受け付けるためのQueueも用意されている。

      val d = Wire(in.d)
      in.d <> Queue(d, 1, flow = true)

APBに関するa_sel, a_enable, a_writeの生成については、以下のように実装されていた。

      val a_enable = RegInit(Bool(false))
      val a_sel    = a.valid && RegNext(!in.d.valid || in.d.ready)
      val a_write  = edgeIn.hasData(a.bits)

      when (a_sel)    { a_enable := Bool(true) }
      when (d.fire()) { a_enable := Bool(false) }

a_selがAssertされるとEnableが立ち上がる。 a_selはdチャネル側の受け入れ準備が出来ていないと立ち上がらない。 a_writea.bitsにデータが入っていないと立ち上がらない。

APBの出力は以下のようになっている。 これは普通の実装に見える。

      out.psel    := a_sel
      out.penable := a_enable
      out.pwrite  := a_write
      out.paddr   := a.bits.address
      out.pprot   := PROT_DEFAULT
      out.pwdata  := a.bits.data
      out.pstrb   := Mux(a_write, a.bits.mask, UInt(0))

読み込みデータが戻ってくるときの実装は以下のようになっている。 まず、DチャネルのOPコードは、読み込みの場合はAccessAck, 書き込みの場合はAccessAckDataが返される。

ID信号とSizeデータはTL2APBユニット内で保持されており、それがそのままキープされる。

データ信号はAPBからのデータがそのまま返される。

      d.bits.opcode  := Mux(d_write, TLMessages.AccessAck, TLMessages.AccessAckData)
      d.bits.param   := UInt(0)
      d.bits.size    := d_size
      d.bits.source  := d_source
      d.bits.sink    := UInt(0)
      d.bits.denied  :=  d_write && out.pslverr
      d.bits.data    := out.prdata
      d.bits.corrupt := !d_write && out.pslverr