FPGA開発日記

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

Spikeのイベントカウンタを使ってRISC-Vの特定の命令のイベントを監視する方法

とある事情でRISC-Vのベクトル命令の実行回数のみを記録したくて、特殊なシステムレジスタを実装するのも厄介なので、RISC-VのイベントカウンタであるHPMCOUNTERシステムレジスタを使うことにした。

Spikeを使っているのだが、HPMCOUNTERシステムレジスタはどうやら固定値になっているらしくカウントアップデートができない。 そこで、CSRの種類を変更してSpikeを再実装する。

以下の変更では、mhpmcounterレジスタを定義したうえで、wise_counter_csr_tで置き換え、カウントアップ機能が使えるようにする。

diff --git a/riscv/processor.cc b/riscv/processor.cc
index c61088c9..a44c9752 100644
--- a/riscv/processor.cc
+++ b/riscv/processor.cc
@@ -264,7 +264,10 @@ void state_t::reset(processor_t* const proc, reg_t max_isa, mmu_t *mmu, uint32_t
     auto mevent = std::make_shared<const_csr_t>(proc, which_mevent, 0);
     auto mcounter = std::make_shared<const_csr_t>(proc, which_mcounter, 0);
     csrmap[which_mevent] = mevent;
-    csrmap[which_mcounter] = mcounter;
+
+    // csrmap[which_mcounter] = mcounter;
+    mhpmcounter[i] = std::make_shared<wide_counter_csr_t>(proc, which_counter);
+    csrmap[which_mcounter] = mhpmcounter[i];

     if (proc->extension_enabled_const(EXT_ZICNTR) && proc->extension_enabled_const(EXT_ZIHPM)) {
       auto counter = std::make_shared<counter_proxy_csr_t>(proc, which_counter, mcounter);
diff --git a/riscv/processor.h b/riscv/processor.h
index 012b56bc..820df0d6 100644
--- a/riscv/processor.h
+++ b/riscv/processor.h
@@ -144,6 +144,7 @@ struct state_t
   csr_t_p mcause;
   wide_counter_csr_t_p minstret;
   wide_counter_csr_t_p mcycle;
+  wide_counter_csr_t_p mhpmcounter[32];
   mie_csr_t_p mie;
   mip_csr_t_p mip;
   csr_t_p medeleg;

このカウントアップ機能を使うためには、wise_counter_csr_tbump()関数を使う。

// vle8.v and vlseg[2-8]e8.v
VI_LD(0, (i * nf + fn), int8, false);
P.get_state()->mhpmcounter[10]->bump(1);

これにより、HMPCOUNTER10がカウントアップされる。あとはこれを観測すればよい。

long long get_vecinst()
{
  long long num;
  asm volatile ("csrr %0, mhpmcounter10":"=r"(num));

  return num;
}

...
    long long start_vecinst = get_vecinst();
...
    printf("vecinst = %ld\n",  end_vecinst - start_vecinst);

これでベクトル命令のイベントをカウントできるようになった。ログを取るのに便利だ。