FPGA開発日記

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

riscv-isa-simのMMUを使用してRTLのMMUを検証する方法の調査

自作RISC-V CPUの検証をするため、SpikeのMMUを使うことを考える。どうしてもTLB周りとか、VA→PAの検証はデバッグが難しい。 ハードウェアが勝手にPage Table Walkして、万が一L1Dキャッシュにデータを書き損じていた場合、波形を一生懸命眺めないと検証できない。

まずは、基本的にTLBの出力結果がISSとあっていなければどうしようもない。この部分のインタフェースを検証するためのDPIを追加することにした。

SpikeのMMUの実装は以下になっている。

github.com

本当はこのtranslate()を使用すればいいのだが、privateなので簡単には使えない。とりあえずpublicに移動して使ってみることにする。

  reg_t translate(reg_t addr, reg_t len, access_type type, uint32_t xlate_flags);

ハードウェア側の実装で、VA→PA変換を行ったときにDPI-Cを呼び出してSpike側のインタフェースを起動するようにしてみる。

reg_t iss_paddr = mmu->translate(rtl_va, rtl_len, static_cast<access_type>(rtl_acc_type), 0);で変換ルーチンを呼び出す。 ちなみに、try - catchを実装しておかないと、Spikeの実装は変換に失敗すると例外を飛ばしてしまうのでしっかりキャッチしておかなければならない。

`ifdef SIMULATION

import "DPI-C" function void check_mmu_trans
  (
   input longint rtl_time,
   input longint rtl_va,
   input int     rtl_len,
   input int     rtl_acc_type,
   input longint rtl_pa
   );

always_ff @ (negedge i_clk, negedge i_reset_n) begin
  if (i_reset_n) begin
    if (i_tlb_req.valid & !w_tlb_miss) begin
      check_mmu_trans ($time, i_tlb_req.vaddr,
                       i_tlb_req.size, i_tlb_req.cmd,
                       o_tlb_resp.paddr);
    end
  end
end

`endif // SIMULATION

C++側の実装は以下のようになった。

void check_mmu_trans (long long time, long long rtl_va,
                      int rtl_len, int rtl_acc_type,
                      long long rtl_pa)
{
  processor_t *p = spike_core->get_core(0);
  spike_core->set_procs_debug(true);
  mmu_t *mmu = p->get_mmu();

  access_type acc_type;
  switch (rtl_acc_type) {
    case 0 : acc_type = LOAD;  break;
    case 1 : acc_type = STORE; break;
    default :
      fprintf (stderr, "rtl_acc_type = %d is not supported\n", rtl_acc_type);
      stop_sim(1);
  }

  try {
    reg_t iss_paddr = mmu->translate(rtl_va, rtl_len, static_cast<access_type>(rtl_acc_type), 0);
    if (iss_paddr != rtl_pa) {
      char spike_out_str[256];
      sprintf (spike_out_str, "Error : PA->VA different.\nRTL = %08x, ISS=%08x",
               rtl_pa, iss_paddr);
      fprintf (compare_log_fp, spike_out_str);
      fprintf (stderr, spike_out_str);
      stop_sim(101);
    } else {
      // fprintf (compare_log_fp, "MMU check passed : VA = %08x, PA = %08x\n", rtl_va, rtl_pa);
    }
  } catch (trap_t &t) {
    // fprintf (compare_log_fp, "Catch exception at check_mmu_trans : VA = %08x, PA = %08x\n", rtl_va, rtl_pa);
  }

  spike_core->set_procs_debug(false);
}

とりあえずここまでで変換ルーチンで、検証できるようになったことは確認した。

ただし、このアサーションをつけてもまだテストパタンのFailを検出することができない。もう少しチェックが必要だ。