FPGA開発日記

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

オープンソース・アウトオブオーダCPU NaxRiscvを概観する (14. FetchPluginをSystemVerilogに変換する)

NaxRiscvの実装を解析しながら、SystemVerilog化することで理解を深めていこうと思う。

FetchPluginは、PCPluginから渡されたPCをもとに命令フェッチを行うモジュールのように思われる。

module NaxRiscv_FetchPlugin
  (
   input logic  i_clk,
   input logic  i_reset_n,

   fetchplugin_if.subordinate fetch_stage0_if,
   fetchcache_if.manager      fetchcache_if,
   lsu2plugin_if.fetch        lsu2_if,
   privileged_if.fetch        privileged_if,
   commit_if.fetch            commit_if,
   envcall_if.fetch           envcall_if,
   mmu_if.fetch               mmu_if,
   btb_if.fetch               btb_if
   );

フェッチステージは0~2の3ステージに分けられており、命令キャッシュやGShare, BTBなどのアクセスも含んでいる。

ちょっと意味不明なのは、GShareのハッシュの計算がPCのビット位置を全て入れ替えたもので行われていること。 これはなんでだろう?

assign _zz_w_stage_0_gshare_hash = fetch_stage0_if.payload.pc[15 : 3];

assign w_stage_0_gshare_hash = _zz_w_stage_0_gshare_hash[0:12] ^ w_stages_0_branch_history[12: 0];

1ステージ目から徐々にSystemVerilogに変換している。例えばステージ1はこんな感じ。

always_ff @ (posedge i_clk) begin
  if(fetch_stage0_if.ready_output) begin
    r_stage1.pc             <= fetch_stage0_if.payload.pc;
    r_stage1.gshare_hash    <= w_stage_0_gshare_hash;
    r_stage1.branch_history <= w_stages_0_branch_history;
    r_stage1.ways           <= w_stage0.ways;
    r_stage1.gshare_bypass  <= w_stage0.gshare_bypass;
  end // if (fetch_stage0_if.ready_output)                                                                                                                                                                                                                                                                                                                                                
end // always_ff @ (posedge i_clk)                                                                                                                                                                                                                                                                                                                                                        

命令フェッチを止める条件はいくつかあるようだ。外部のモジュールからのhaltreqに応じて命令フェッチを止める。

assign w_haltreq_fetchcache_0 = !fetchcache_if.invalidate_done || fetchcache_if.invalidate_requested;
assign w_haltreq_fetchcache_1 = fetchcache_if.refill_valid;
assign w_haltreq_fetchcache_2 = fetchcache_if.read_ctrl_redoIt;
assign w_haltreq_fetchcache_3 = !fetchcache_if.translationPort_wake;
assign w_haltreq_lsu          = lsu2_if.flush_busy;
assign w_haltreq_privileged   = (priviledged_if.state != NaxRiscv_pkg::PrivilegedIDLE) |
                                (commit_if.reschedule_valid && commit_if.reschedule_trap));
assign w_haltreq_envcall    = envcall_if.flushes_state != NaxRiscv_pkg::EnvCallIDLE;
assign w_haltreq_mmu        = !mmu_if.invalidate_done || mmu_if.invalidate_requested;

assign when_Pipeline_l278_9 = w_haltreq_mmu | w_haltreq_envcall | w_haltreq_privileged | w_haltreq_lsu |
                              w_haltreq_fetchcache_0 | w_haltreq_fetchcache_1 | w_haltreq_fetchcache_2 | w_haltreq_fetchcache_3;

次のステージの実装も、少しずつ進めていこう。