Rocket-Chip / BOOMのTLBについてはある程度動作を理解できるようになってきたので、次はTLBがつながる先のPTW (Page Table Walker)について調査したい。Page Table Walkerは基本的にRocketTile / BoomTileに1つだけ搭載されているが、ポートはTLBの数だけ用意されている。つまり、ITLB / DTLBの2つがコア内に搭載されているならば、PTWにはリクエストを受け付けるためのポートが2つ用意される仕組みになっているようだ。
PTWのインタフェースは以下のようになっている。
rocket-chip/src/main/scala/rocket/PTW.scala
class PTW(n: Int)(implicit edge: TLEdgeOut, p: Parameters) extends CoreModule()(p) { val io = new Bundle { // リクエスト:複数のリクエストを受け付ける val requestor = Vec(n, new TLBPTWIO).flip // メモリアクセスインタフェース val mem = new HellaCacheIO // コアからの情報インタフェース val dpath = new DatapathPTWIO }
内部にはリクエストのアービトレーションを行うためのArbiterが搭載されており、これによりどのリクエストを受け取るかを決定する。このArbtrationに負けたリクエストは、勝つまでリクエストを要求することになる。
// リクエストのアービトレーション val arb = Module(new Arbiter(Valid(new PTWReq), n)) arb.io.in <> io.requestor.map(_.req) arb.io.out.ready := (state === s_ready) && !l2_refill_wire
内部にはステートマシンが入っており、もしL2TLBにヒットしない場合には外部にメモリリクエストを発行するようになっている。ページテーブルアクセスは複数のメモリアクセスリクエストが必要になるので、メモリリクエストを発行しながらステートマシンを遷移させ、最終的なPTEまで到達させるという仕組みのようだ。L2TLBの構成を除けば、そこまで難しくはないように感じる。
ただしこのPTWのアクセスはL1DやICacheを経由しないので、L2に到達したらL1Dに入っているデータをチェックするプロトコルは必要なんだろうな。これはおそらくTileLinkで実装されている。