FPGA開発日記

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

riscv-isa-simのメモリモデルを使用してRTLのメモリアクセスを検証する方法の調査

自作RISC-V CPUの検証をするため、メモリアクセスをSpikeで検証することを考える。 L1Dのアップデートのタイミングで、現状のメモリの状態を確認することを考えてみよう。

いくつかのチェックポイントがあるはずだ。

  • L1Dからデータを外部に吐き出すタイミング
  • L1Dにデータをロードするタイミング
  • ストア命令がL1Dをアップデートするタイミング

まずは一番簡単そうな、L1Dの外部吐き出しのタイミングでSpikeのチェックを実行することを考える。 基本的な方針としては、メモリサブシステムがキャッシュラインの吐き出しをするタイミングでDPI-Cを呼び出し、Spikeのメモリ状態と比較する。

always_ff @ (negedge i_clk, negedge i_reset_n) begin
  if (i_reset_n) begin
    if (l1d_ext_wr_req.valid & l1d_ext_wr_req.ready) begin
      /* verilator lint_off WIDTH */
      record_l1d_evict ($time,
                        l1d_ext_wr_req.payload.addr,
                        l1d_ext_wr_req.payload.addr[$clog2(DCACHE_DATA_B_W) +: DCACHE_TAG_LOW],
                        l1d_array,
                        DCACHE_DATA_B_W);

このタイミングで、Spike経由でメモリの内容を参照する。

  bool diff_found = false;
  fprintf(compare_log_fp, "%lld : EVict ISS Check : %llx        : ", rtl_time, paddr);
  try {
    for (int i = size/8-1; i >= 0; i--) {
      uint64_t iss_ld_data;
      spike_core->read_mem(paddr + i * 8, 8, &iss_ld_data);
      fprintf(compare_log_fp, "%08x_%08x", iss_ld_data >> 32 & 0xffffffff, iss_ld_data & 0xffffffff);
      if ((iss_ld_data >> 32 & 0xffffffff) != l1d_data[i*2+1] |
          (iss_ld_data & 0xffffffff) != l1d_data[i*2+0]) {
        diff_found = true;
      }
      if (i != 0) {
        fprintf(compare_log_fp, "_");
      }
    }
    fprintf(compare_log_fp, "\n");
  } catch (trap_t &t) {
    fprintf (compare_log_fp, "Catch exception at record_l1d_evict : PA = %08llx, %s\n", paddr, t.name());
  }

  if (diff_found) {
    fprintf (compare_log_fp, "Eviction Data Compare Error\n");
    stop_sim (102);
  }

spike_core->read_mem()マッピングしているけれど、実体はsim_tread_chunk()を呼び出している。

  void read_mem(addr_t taddr, size_t len, void* dst) {
    read_chunk (taddr, len, dst);
  }

いろいろ調べてみると、Spikeの環境には2種類のMMUが用意されていて、

  • sim_t::debug_mmu グローバルなMMU。アクセスは物理アドレスで行う
  • sim_t::core::mmu 各コアでのMMU。アクセスは仮想アドレスで行う

という感じがしているので、グローバルなMMUを使用して正確な物理アドレスを使用するのがポイント。

この仕様は、Spikeのインタラクティブモードで物理アドレスを使うことができるので、どこかにそういう機能があるはずだと探して見つかった。

To see the contents of a memory location (physical address in hex):

: mem 2020
To see the contents of memory with a virtual address (0 for core 0):

: mem 0 2020