BOOMv3のフロントエンド、特に分岐予測の部分についてちょっと実装を確認したくなった。 以下ドキュメントとソースコードを読んだ時のメモ。続き。
RASのアップデートのタイミング
読み込みのタイミング。f3
のタイミングでRASを読んでいる。それと同時にras_read_idx
レジスタのアップデートを行っている。
ポイントとなるのは、Global History TableからRASのインデックスを引いてきている、ということか?
// RAS takes a cycle to read val ras_read_idx = RegInit(0.U(log2Ceil(nRasEntries).W)) ras.io.read_idx := ras_read_idx when (f3.io.enq.fire()) { ras_read_idx := f3.io.enq.bits.ghist.ras_idx ras.io.read_idx := f3.io.enq.bits.ghist.ras_idx }
おや、同じサイクルでRASを読み込んでいるようだ。ret命令の場合はRASの値ras.io.read_addr
を使用している。
f3_fetch_bundle.ras_top := ras.io.read_addr // Redirect earlier stages only if the later stage // can consume this packet val f3_predicted_target = Mux(f3_redirects.reduce(_||_), Mux(f3_fetch_bundle.cfi_is_ret && useBPD.B && useRAS.B, ras.io.read_addr, f3_targs(PriorityEncoder(f3_redirects)) ), nextFetch(f3_fetch_bundle.pc) )
次に書き込みのタイミングだが、f3のBTB Response Queueを抜けた時点ですぐに書き込むようだ。
ras.io.write_valid := false.B ras.io.write_addr := f3_aligned_pc + (f3_fetch_bundle.cfi_idx.bits << 1) + Mux( f3_fetch_bundle.cfi_npc_plus4, 4.U, 2.U) ras.io.write_idx := WrapInc(f3_fetch_bundle.ghist.ras_idx, nRasEntries) /* 途中省略 */ when (f3.io.deq.valid && f4_ready) { when (f3_fetch_bundle.cfi_is_call && f3_fetch_bundle.cfi_idx.valid) { ras.io.write_valid := true.B }
一方で、FTQを通じてバックエンドからも更新通知がやってくる。
when (ftq.io.ras_update && enableRasTopRepair.B) {
ras.io.write_valid := true.B
ras.io.write_idx := ftq.io.ras_update_idx
ras.io.write_addr := ftq.io.ras_update_pc
}