FPGA開発日記

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

自作RISC-V CPUコア実装(RET命令の再考)

自作CPUの実装、ロードストア命令の物理アドレスが決まらないうえでのハザードのボトルネックを解決した。 そうこうしているうちにいつの間にかRET命令のRAS予測が怪しくなってきているので修正しておきたい。

フロントエンドのパイプラインステージをs0, s1, ... と表記すると、これまではBTBとBIMの参照をs0で行い、その結果s1でBTBの結果からそのまま分岐予測を実行していた。この方式は遅延なく分岐予測を実行できるのがメリットだが、RET命令の検出は命令キャッシュから命令を取得するまで分からないので、RASがあまり活用されていない。

命令キャッシュからデータを取得するのはs2ステージのため、s2ステージからも分岐予測を実行してフェッチアドレスを更新できるように変更してみる。こうすることで、RET命令は1サイクル遅れて分岐予測を行うので、性能的には他の分岐命令に比べて1サイクル遅れることになるが、完全にパイプラインフラッシュするよりかはマシなはずだ。

分岐命令のフロントエンドを以下のように変更して、s1ステージ、s2ステージのどちらからも分岐予測を適用可能にしてみる。 s2ステージにおいてRET命令のRASによる予測を行うと、自動的にその一つ先のs1ステージはフラッシュする。

diff --git a/src/msrh_frontend.sv b/src/msrh_frontend.sv
index 1b1e859..5583f37 100644
--- a/src/msrh_frontend.sv
+++ b/src/msrh_frontend.sv
@@ -86,6 +86,11 @@ logic                          r_s1_tlb_miss;
 logic                          r_s1_tlb_except_valid;
 msrh_pkg::except_t             r_s1_tlb_except_cause;

+logic [riscv_pkg::VADDR_W-1: 0] w_s1_btb_target_vaddr;
+
+logic                           w_s1_predict_valid;
+logic [riscv_pkg::VADDR_W-1: 0] w_s1_predict_target_vaddr;
+
 // ==============
 // s2 stage
 // ==============
@@ -101,10 +106,8 @@ logic                           r_s2_tlb_miss;
 logic                           r_s2_tlb_except_valid;
 msrh_pkg::except_t              r_s2_tlb_except_cause;

-logic [riscv_pkg::VADDR_W-1: 0] w_s1_btb_target_vaddr;
-
-logic                           w_s1_predict_valid;
-logic [riscv_pkg::VADDR_W-1: 0] w_s1_predict_target_vaddr;
+logic                           w_s2_predict_valid;
+logic [riscv_pkg::VADDR_W-1: 0] w_s2_predict_target_vaddr;

 // =======================
 // Predictors
@@ -310,6 +313,9 @@ always_comb begin
           w_s0_vaddr_next = {w_s2_ic_resp.vaddr, 1'b0};
           w_if_state_next = WAIT_IBUF_FREE;
         end
+      end else if (w_s2_predict_valid) begin
+        w_s0_vaddr_next = (w_s2_predict_target_vaddr & ~((1 << $clog2(msrh_lsu_pkg::ICACHE_DATA_B_W))-1)) +
+                          (1 << $clog2(msrh_lsu_pkg::ICACHE_DATA_B_W));
       end else if (w_s1_predict_valid) begin
         w_s0_vaddr_next = (w_s1_predict_target_vaddr & ~((1 << $clog2(msrh_lsu_pkg::ICACHE_DATA_B_W))-1)) +
                           (1 << $clog2(msrh_lsu_pkg::ICACHE_DATA_B_W));
@@ -596,6 +602,9 @@ assign w_s1_predict_valid = w_s1_inst_valid &
 assign w_s1_predict_target_vaddr = |w_ras_search_if.s1_is_ret ? {w_ras_search_if.s1_ras_vaddr, 1'b0} :
                                    w_s1_btb_target_vaddr;

+assign w_s2_predict_valid        = w_s2_inst_valid & (|w_ras_search_if.s2_is_ret);  // from RAS
+assign w_s2_predict_target_vaddr = {w_ras_search_if.s2_ras_vaddr, 1'b0};
+

 msrh_predictor u_predictor
   (