FPGA開発日記

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

オープンソース・アウトオブオーダCPU NaxRiscvを概観する (PLRUのソースコードを概観する)

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

FetchCachePluginには、どのWayを置き換えるのかを計算するPLRUのコードが示されている。 いろいろ解析するとこれはTree PLRUを実装しているコードのようだ。しかしSpinal HDLのコードが意味不明すぎて良く理解できていない。

en.wikipedia.org

EvictionとUpdateのロジックに分かれていて、最初はUpdateの論理でPLRUのポインタを更新するのかと思ったら違うらしい。

なんか良く分からないのでChatGPTに実装をVerilog-HDLに変換してもらった。

module Plru #(
  parameter int ENTRIES = 4,               // Number of cache entries, must be a power of 2
  parameter bit WITH_ENTRIES_VALID = 0     // Flag to enable valid entry checking
)(
  input  logic [log2(ENTRIES)-1:0] update_id,       // ID of the accessed entry
  input  logic [log2(ENTRIES)-1:0] context_state [log2(ENTRIES)-1:0],  // Current PLRU tree state
  input  logic [ENTRIES-1:0] context_valids,        // Valid entries for replacement check
  output logic [log2(ENTRIES)-1:0] evict_id,        // ID of the entry to evict
  output logic [log2(ENTRIES)-1:0] update_state [log2(ENTRIES)-1:0]    // Updated PLRU tree state
);

  logic [log2(ENTRIES)-1:0] sel [log2(ENTRIES)-1:0];   // Selection bits for eviction
  logic [log2(ENTRIES)-1:0] new_state [log2(ENTRIES)-1:0]; // Internal state for update logic

  // Eviction Logic
  generate
    genvar i;
    for (i = 0; i < log2(ENTRIES); i = i + 1) begin : eviction_logic
      logic [i:0] state_sel;
      assign state_sel = sel[i-1:0];  // Selection path based on previous sel values

      always_comb begin
        sel[i] = ~context_state[i][state_sel];  // Invert the state to select LRU path
      end

      if (WITH_ENTRIES_VALID) begin : valid_check
        // Ensure only valid entries are considered for eviction
        logic [1:0] notOks;
        assign notOks[0] = |context_valids[state_sel * 2 +: 2];  // Check valid entries in the group
        sel[i] = notOks[0] ? 0 : sel[i];
      end
    end
  endgenerate

  assign evict_id = sel[log2(ENTRIES)-1];  // The final eviction ID is based on the selection path

  // Update Logic
  generate
    for (i = 0; i < log2(ENTRIES); i = i + 1) begin : update_logic
      always_comb begin
        if (i == 0) begin
          update_state[i] = context_state[i];  // Preserve current state for higher levels
        end
        update_state[i][update_id[log2(ENTRIES)-1:i]] = update_id[log2(ENTRIES)-1-i];  // Update state
      end
    end
  endgenerate

endmodule