FPGA開発日記

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

SonicBOOMの分岐命令管理に関する調査

SonicBOOMに限らず、多くのOoOプロセッサには分岐命令管理用のタグが付いているという認識だ。brtagと一般的に呼ばれているこのタグは、分岐命令に対してそれぞれ付与されており、また分岐命令以外の命令にも一貫して付与されている。分岐タグは「この命令はどの分岐命令に依存しているか」というのを示すためのものであり、単純に言うならば、分岐タグ5が付けられた分岐命令が予測に失敗しパイプラインをフラッシュした場合、分岐タグ6以降の命令はすべてフラッシュする、という形で命令を管理する。

// 分岐タグ5
add  x10, x11, x12
sub  x30, x31, x1
beq  x1, x2, label  // ここまでが分岐タグ5
// 分岐タグ6
mul  x10, x11, x12
div  x2, x3, x4
bne  x5, x6            // ここまでが分岐タグ6
// ここから先が分岐タグ7

上記の例では、もし分岐タグ5の分岐命令beqが予測に失敗した場合、分岐タグ6移行のタグが付けられた命令をフラッシュすることで命令実行をやり直すという仕組みになっている。

「コミットIDを使ってフラッシュすれば良いじゃないか」というのもあるが、その場合コミットが発生するまでパイプラインをフラッシュできない。分岐タグは、分岐命令の実行が完了した段階ですぐにフラッシュを発生できるので、再実行までのタイミングがコミットIDを使うよりも早いという利点がある。

さて、SonicBOOMにも分岐タグが採用されている。アーキテクチャの仕様としては以下に説明がなされている。

docs.boom-core.org

If the branches (or jumps) have been correctly speculated by the Front-end, then the Branch Unit s only action is to broadcast the corresponding branch tag to all inflight UOPs<Micro-Op (UOP) that the branch has been resolved correctly. Each UOP<Micro-Op (UOP) can then clear the corresponding bit in its branch mask, and that branch tag can then be allocated to a new branch in the Decode stage.

If a branch (or jump) is misspeculated, the Branch Unit must redirect the PC to the correct target, kill the Front-end and Fetch Buffer, and broadcast the misspeculated branch tag so that all dependent, inflight UOPs<Micro-Op (UOP) may be killed. The PC redirect signal goes out immediately, to decrease the misprediction penalty. However, the kill signal is delayed a cycle for critical path reasons.

これだけではさっぱり分からないのでCoremarkを実行して波形を観測してみよう。

f:id:msyksphinz:20210625002006p:plain

branch_maskというのが、タグが分岐命令により現在使用中かどうかを示すビット。ここではbranch_mask[11:0]なので最大で12個の分岐タグを使用することができる。デコード時に分岐命令に遭遇すると、新しい分岐タグを取得してbranch_maskの当該ビットを1に設定し、分岐命令の実行完了すると落とす。つまり、このデザインではパイプライン中にInflightできる分岐命令は最大で12個に制限されるということが分かる(と言ってもスケジューラのスロットの方が少ないかもしれないが)。

分岐命令がデコードされると、新たに分岐タグが割り当てられる(下図のio_br_tag_0io_br_tag_1がそれに相当する)。それと同時に「その分岐命令が実行されるまでにInflightになった分岐命令のビットパタンも同時に渡される(下図のio_br_mask_0io_br_mask_1がそれに相当する)。これは、デコードされた分岐命令よりも以前に実行された分岐命令のタグを示している。つまり、もし当該分岐命令が分岐予測ミスを起こした場合、その命令に付属するbrmaskが0になっている(つまり当該分岐命令をデコード後に新たに割り当てられた可能性のある若い分岐命令)は確実にフラッシュされる。逆に言うと、brmaskが1になっているタグは当該分岐命令よりも古いので、フラッシュの対象になるとは限らない。

f:id:msyksphinz:20210625001800p:plain

分岐命令の実行が完了すると、それぞれの分岐命令はi_brupdate_b1_resolve_maskio_brupdate_b2_xxxの信号を用いて分岐命令の実行結果を通知する。resolveは基本的にOneHotな信号(同時に複数の分岐命令が実行完了するとそうではなくなる)で、この通知に呼応してbranch_maskのビットが下げられる。

その1サイクル後に、Mispredictionの信号が通知される、上記の例では、io_brupdate_b2_mispredictが1に設定され、io_brupdate_b2_uop_br_maskに値が設定されている。 このio_brupdate_b2_uop_br_maskは、分岐タグフラッシュが発生した際に生き残って欲しい分岐タグを示している。つまり、当該分岐命令よりも「古い」命令が生き残るように設定される。

f:id:msyksphinz:20210625001819p:plain

しかし一方で当該タグ10の分岐命令をデコードした時にはbrmaskは0xbbfが渡されていたではないか?なぜbbeに値が変わってしまっているのか。

これはおそらく、分岐タグ0の命令が分岐タグ10よりも先に解決してしまったからだろう。ビット0はビット10がフラッシュする前に解決し、0に下げられている。したがってこれを別の分岐命令が監視しており、「分岐タグ0は解決したのでもう生き残らせる必要はない」ということで0に落としてしまったものと思われる。

f:id:msyksphinz:20210625001839p:plain