FPGA開発日記

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

自作RISC-Vアウトオブオーダコアの実装 (分岐の高速化2)

CALLとRETの問題について、もう少しアサーションを組みながら徹底的に解析していたのだが、何となく問題が分かってきた。

RISC-Vの命令は32ビットが基本なのだが、RVC命令をサポートするために16ビット境界に配置することができる。この時、この16ビット境界に配置されたCALL命令とRET命令をどのように識別するかというのが問題になる。 キャッシュラインを跨いでいるので認識が大変なのだが、一つの方法としては、前のキャッシュラインの最上位の16ビットを覚えておき、次のキャッシュラインの下位の16ビットと合わせて比較する。これによりキャッシュラインを跨いでも正確にCALLとRETを見つけだすことが出来るようになる。

もう一つの問題は、CALLやRETが投機的に実行されてしまいRASのインデックスの場所がくるってしまうことだが、これは投機実行しても、コミット時のフラッシュや分岐予測ミスが発生した場合に、最新のCALL/RETの場所まで戻るように論理を組みなおすことによりインデックスが狂わなくなった。

Dhrystoneを実行してみると、とりあえずこれらの関数呼び出しと関数から戻る処理は殆どミスしないようになった。

             1013526 : (09,1) pc_vaddr = 0000000080002202, target_addr = 00000000800020b8, pred_target_addr = 00000000800020b8, ras_index =  2, Succ, jal     pc - 0x14a
             1013554 : (13,1) pc_vaddr = 00000000800020c4, target_addr = 00000000800020b0, pred_target_addr = 00000000800020b0, ras_index =  3, Succ, jal     pc - 0x14
             1013562 : (15,2) pc_vaddr = 00000000800020b6, target_addr = 00000000800020c8, pred_target_addr = 00000000800020c8, ras_index =  3, Succ, ret
             1013606 : (07,1) pc_vaddr = 0000000080002118, target_addr = 0000000080002206, pred_target_addr = 0000000080002206, ras_index =  2, Succ, ret
             1013686 : (03,1) pc_vaddr = 0000000080002006, target_addr = 0000000080002bc6, pred_target_addr = 0000000080002bc6, ras_index =  1, Succ, ret
             1013738 : (09,2) pc_vaddr = 0000000080002bee, target_addr = 0000000080002052, pred_target_addr = 0000000080002052, ras_index =  1, Succ, jal     pc - 0xb9c
             1013758 : (12,2) pc_vaddr = 0000000080002060, target_addr = 0000000080002bf2, pred_target_addr = 0000000080002bf2, ras_index =  1, Succ, ret
             1013834 : (06,2) pc_vaddr = 0000000080002bee, target_addr = 0000000080002052, pred_target_addr = 0000000080002052, ras_index =  1, Succ, jal     pc - 0xb9c
             1013862 : (09,2) pc_vaddr = 0000000080002060, target_addr = 0000000080002bf2, pred_target_addr = 0000000080002bf2, ras_index =  1, Succ, ret
             1013954 : (06,2) pc_vaddr = 0000000080002c68, target_addr = 000000008000213c, pred_target_addr = 000000008000213c, ras_index =  1, Succ, jal     pc - 0xb2c
             1014126 : (03,1) pc_vaddr = 000000008000215e, target_addr = 0000000080002c6c, pred_target_addr = 0000000080002b26, ras_index =  1, Miss, ret
             1014170 : (08,1) pc_vaddr = 0000000080002b22, target_addr = 000000008000224e, pred_target_addr = 000000008000224e, ras_index =  1, Succ, jal     pc - 0x8d4
             1014238 : (12,2) pc_vaddr = 0000000080002262, target_addr = 0000000080002b26, pred_target_addr = 0000000080002b26, ras_index =  1, Succ, ret
             1014246 : (13,1) pc_vaddr = 0000000080002b26, target_addr = 0000000080002222, pred_target_addr = 0000000080002222, ras_index =  1, Succ, jal     pc - 0x904
             1014326 : (06,1) pc_vaddr = 000000008000224c, target_addr = 0000000080002b2a, pred_target_addr = 0000000080002b2a, ras_index =  1, Succ, ret
             1014510 : (04,2) pc_vaddr = 0000000080002b6a, target_addr = 000000008000206e, pred_target_addr = 000000008000206e, ras_index =  1, Succ, jal     pc - 0xafc
             1014546 : (09,2) pc_vaddr = 0000000080002082, target_addr = 0000000080002052, pred_target_addr = 0000000080002052, ras_index =  2, Succ, jal     pc - 0x30
             1014574 : (12,2) pc_vaddr = 0000000080002060, target_addr = 0000000080002086, pred_target_addr = 0000000080002086, ras_index =  2, Succ, ret
             1014598 : (15,2) pc_vaddr = 000000008000208e, target_addr = 00000000800028e6, pred_target_addr = 00000000800028e6, ras_index =  2, Succ, jal     pc + 0x858
             1014630 : (05,2) pc_vaddr = 00000000800028fe, target_addr = 0000000080002092, pred_target_addr = 0000000080002092, ras_index =  2, Succ, ret

それでも時々Missが起きる。これはおそらく 1. CALLの投機実行:エントリ1を書き換え 2. RETの投機実行:エントリ1を使用 3. CALLの投機実行:エントリ1を書き換え 4. 投機実行ミス。2./3. が廃棄される 5. RETの投機実行。エントリ1を使用したが3.により書き換えられている

というシーケンスが発生しているものと思われる。念のため確認した方がいい気がするが、とりあえずほとんどの場合で予測に成功しているのでとりあえず良しと使用かな...