BOOMのTLBの調査を引き続き行っている。TLBミスを起こしたリクエストはPTW(Page Table Walker)に渡されるのだが、Page Table Walkerのバッファにもヒットしなかった場合には外部にリクエストが渡される。外部リクエストがどこに行くのか観察していた。
最初はPTWのリクエストはコアの外(Tileの外)に向かうのかと思っていたのだが、そうではなくLSUポートを通じてまずはL1Dキャッシュへのアクセスを行うらしい。当初の予想は、Tileから外に向かって、TileのL2がエントリの有り無しを確認した後コアに確認のプローブシグナルを送るのかと思っていたのだが、まずはL1Dに確認が入るということか。
そして、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に直接確認することで取得できるようになるという訳だ。