FPGA開発日記

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

BOOMのTLBに関する調査 (7. PTWからLSUへのインタフェース)

BOOMのTLBの調査を引き続き行っている。TLBミスを起こしたリクエストはPTW(Page Table Walker)に渡されるのだが、Page Table Walkerのバッファにもヒットしなかった場合には外部にリクエストが渡される。外部リクエストがどこに行くのか観察していた。

最初はPTWのリクエストはコアの外(Tileの外)に向かうのかと思っていたのだが、そうではなくLSUポートを通じてまずはL1Dキャッシュへのアクセスを行うらしい。当初の予想は、Tileから外に向かって、TileのL2がエントリの有り無しを確認した後コアに確認のプローブシグナルを送るのかと思っていたのだが、まずはL1Dに確認が入るということか。

f:id:msyksphinz:20210516215255p:plain

そして、LSUモジュールの中でさらにリクエストのアービトレーションが入り、そしてL1Dにもヒットしない場合はLSUを経由して外部にリクエストが向かう。

なるほど、BOOMのTileはLSUのアクセスポートを1つしか持っていないということか。まあ確かにTileLinkのポートはBOOM Tileで1セットにしたいのでここでリクエストのポートを1つに統一しておくのは分かる気がする。

まず、PTWからのリクエストをHellaCacheIOに接続する。そしてHellaCacheIOが複数用意されている場合はArbiterを挿入するということになる。

  • src/main/scala/common/tile.scala
  // PTW
  val ptw  = Module(new PTW(ptwPorts.length)(outer.dcache.node.edges.out(0), outer.p))
  core.io.ptw <> ptw.io.dpath
  ptw.io.requestor <> ptwPorts
  hellaCachePorts += ptw.io.mem

そしてhellaCachePortsがLSUに挿入される。

   // LSU IO
  val hellaCacheArb = Module(new HellaCacheArbiter(hellaCachePorts.length)(outer.p))
  hellaCacheArb.io.requestor <> hellaCachePorts
  lsu.io.hellacache <> hellaCacheArb.io.mem
  outer.dcache.module.io.lsu <> lsu.io.dmem

lsu.io.hellacacheのリクエストはArbitrationされ、LSU内部でリクエストとしてマージされる。

  • src/main/scala/lsu/lsu.scala
  // -----------------------
  // Hellacache interface
  // We need to time things like a HellaCache would
  io.hellacache.req.ready := false.B
  io.hellacache.s2_nack   := false.B
  io.hellacache.s2_xcpt   := (0.U).asTypeOf(new rocket.HellaCacheExceptions)
  io.hellacache.resp.valid := false.B
  when (hella_state === h_ready) {
    io.hellacache.req.ready := true.B
    when (io.hellacache.req.fire()) {
      hella_req   := io.hellacache.req.bits
      hella_state := h_s1
    }
  } .elsewhen (hella_state === h_s1) {
// 中略

hella_reqのコマンドは他のLSU内のコマンドとアービトレーションされ、LSU内部で伝えられる。

  val exe_size   = widthMap(w =>
                   Mux(will_fire_load_incoming (w) ||
                       will_fire_stad_incoming (w) ||
                       will_fire_sta_incoming  (w) ||
                       will_fire_sfence        (w) ||
                       will_fire_load_retry    (w) ||
                       will_fire_sta_retry     (w)  , exe_tlb_uop(w).mem_size,
                   Mux(will_fire_hella_incoming(w)  , hella_req.size,
                                                      0.U)))
  val exe_cmd    = widthMap(w =>
                   Mux(will_fire_load_incoming (w) ||
                       will_fire_stad_incoming (w) ||
                       will_fire_sta_incoming  (w) ||
                       will_fire_sfence        (w) ||
                       will_fire_load_retry    (w) ||
                       will_fire_sta_retry     (w)  , exe_tlb_uop(w).mem_cmd,
                   Mux(will_fire_hella_incoming(w)  , hella_req.cmd,
                                                      0.U)))

ちなみに、リクエストアドレスはvaddrとして挿入されるが、LSU内部ではpassthrough=1としてTLBに渡されるので、そのままPTWのリクエストアドレスが物理アドレスとして処理されることになる。

  val exe_passthr= widthMap(w =>
                   Mux(will_fire_hella_incoming(w)  , hella_req.phys,
                                                      false.B))
  val exe_kill   = widthMap(w =>
                   Mux(will_fire_hella_incoming(w)  , io.hellacache.s1_kill,
                                                      false.B))

これでPTWのリクエストは、一端コアを出ずにL1Dに直接確認することで取得できるようになるという訳だ。