FPGA開発日記

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

自作CPUコアにRISC-Vベクトル命令を載せるための検討

RISC-Vのベクトル命令を実装する場合、まず考えなければならないのはVSETVL命令をどのように乗せるのかという点だ。VSETVL系統の命令はループのたびに高頻度で実行されるので、これを高速に動かす必要がある。

このため、RVV仕様におけるVL/VTYPEレジスタをリネームするというのは割と一般的に行われているようだ。 VL/VTYPEを複数持つことによって、可能な限りこれらのシステムレジスタを投機的に計算して保持し、ベクトル命令の計算を高速化する。

まず、この構成を考えた。VSETVL命令がデコードされると、この情報に基づいてすぐに新しいVL/VTYPE物理システムレジスタを割り当てる。 最初はこの割り当てのためにフリーリストが必要かも、と考えたが、よく考えたらいらない。デコード時に確保してコミット時に開放するので、インオーダでの割り当てで十分なのだ。また、1種類のレジスタを割り当てなおしているので、汎用レジスタのフリーリストのように複雑なことをする必要がない。

これに従って、簡単にVSETVLI命令自作CPUに実装して、動作を確認してみた。VSETVLI命令はシステムレジスタをたたくのでCSUパイプラインを使う。 CSUパイプラインは常にUncommitted Oldest状態にならなければ発行されない構成になっていたが、これも変更した。

#include <riscv_vector.h>
#include <stddef.h>

int main ()
{
  const int n = 100;

  size_t vl;
  for (int i = 0; i < n; i += vl) {
    vl = __riscv_vsetvl_e64m1(n - i);
  }

  for (int i = 0; i < n; i += vl) {
    vl = __riscv_vsetvl_e32m1(n - i);
  }

  for (int i = 0; i < n; i += vl) {
    vl = __riscv_vsetvl_e16m1(n - i);
  }

  for (int i = 0; i < n; i += vl) {
    vl = __riscv_vsetvl_e8m1(n - i);
  }

これくらいのループならばすぐに回せる。VSETVLIは3サイクルに1回アップデートすることが可能で、これで十分だろう。