UCBの開発しているシミュレータSpikeは、RISC-Vの命令セットをシミュレーションすることのできるISSで、サイクル精度を出すことはできないが最初のアプリケーションのデバッグに有用なツールだ。
そして、RISC-Vにはカスタム命令 (custom0 - custom3)が用意されており、Rocket Chipの場合にはこの命令フィールドを用いてRoCCインタフェース上にアクセラレータを搭載することが出来る。
どうせ元はChiselなのだから、この辺をうまくマージすることが出来ないだろうかといろいろ調査していたのだが、どうやらRoCCインタフェースをSpikeシミュレータではシミュレーションすることが出来るようだ。
今回はmemtotal_rocc.cc を作成してディレクトリを作成しビルドした。32ビット整数のDotProductを計算する回路(Chiselで作成したもの)と同一のものをビルド作成した。
riscv-tools/riscv-isa-sim/memtotal_rocc/memtotal_rocc.cc
class memtotal_rocc_t : public rocc_t { public: const char* name() { return "memtotal_rocc"; } reg_t custom0(rocc_insn_t insn, reg_t xs1, reg_t xs2) { reg_t total = 0; switch (insn.funct) { case 0: c0_reg_lengthM = xs1; break; case 1: c0_reg_lengthK = xs1; break; case 2: { reg_t total_lo = 0, total_hi = 0; reg_t xs1_p = xs1, xs2_p = xs2; for (reg_t i = 0; i < c0_reg_lengthM; i++) { total_lo += p->get_mmu()->load_int32(xs1_p) * p->get_mmu()->load_int32(xs2_p); xs1_p += sizeof(int32_t); xs2_p += c0_reg_lengthK * sizeof(int32_t); } xs1_p = xs1; xs2_p = xs2 + sizeof(int32_t); for (reg_t i = 0; i < c0_reg_lengthM; i++) { total_hi += p->get_mmu()->load_int32(xs1_p) * p->get_mmu()->load_int32(xs2_p); xs1 += sizeof(int32_t); xs2 += c0_reg_lengthK * sizeof(int32_t); } total = ((total_hi & 0x0ffffffffUL) << 32) | (total_lo & 0x0ffffffffUL); break; } } return total; }
一度build.sh
を実行しないとちゃんと動作しなかった。このへんはもうちょっとビルドフローを調査する必要がある。ともかく、roccインタフェースをC++で記述するとRoCCの動作をC++で記述することが出来る。
拡張として memtotal_rocc
のライブラリを指定するとちゃんとRoCCアクセラレータの実装をSpikeで実行することが出来る。これは面白い。
./spike --extension=memtotal_rocc /home/msyksphinz/riscv64/riscv64-unknown-elf/share/riscv-tests/benchmarks/test-matrixmul32.riscv```
追記: libmemtotal_rocc.so のビルドが可能なプロジェクトをgithubに置きました。