FPGA開発日記

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

RISC-V Vector Extension v0.9のCSR仕様2

RISC-Vのベクトル拡張の理解に当たり、複雑怪奇なシステムレジスタを理解するのは大変だ。ここではRISC-Vベクトル拡張が備える謎のシステムレジスタについて一気に解説していきたい。

ちなみに最新のRISC-V Vector Extension 0.9をベースに解説している。


RISC-V Vector Extension 0.9では以下に示すCSRを新たに定義している。

f:id:msyksphinz:20200710010429p:plain
  • vstartシステムレジスタ

ベクトルレジスタに処理を適用する場合、最初のいくつかのベクトル要素の処理を省略するためのシステムレジスタ。vstart !=0 が設定されていると、ベクトルレジスタの最初の要素は処理が行われない。

これと似たような機能に、「ベクトルレジスタマスク」がある。ベクトルレジスタマスクはvmとして表現され、RVV 0.9では常にv0がマスクレジスタとして使用される仕組みになっている。ベクトル命令のエンコーディングのうち25ビット目がvmレジスタの有効無効に使用され、vmが適用されるとv0レジスタのエンコーディングに従って特定のベクトル要素の処理を無効化することができる。

f:id:msyksphinz:20200710232923p:plain
vle32.v vd,(rs1),v0.t    # ベクトルマスク有効
vle32.v vd,(rs1)         # ベクトルマスク無効

一方でvstartシステムレジスタは使用目的が異なる。ベクトル拡張命令ではメモリアクセスによる例外が発生した場合に例外にジャンプするが、その時に「どの場所までベクトル要素を操作したか」を記憶するためにvstartが使用される。例外処理ルーチンの中でしかるべき処理を行った後に例外から復帰して再度ベクトル命令を実行する場合に、vstart != 0ならばその要素から処理が再開される。つまり、vstartは例外から復帰をサポートするためのレジスタとなっている。

この目的に沿うため、vstartシステムレジスタは、ベクトル命令を正常に完了すると常にvstart=0に設定されるようになっている。例外が発生したときのみ設定されるという仕組みだ。

f:id:msyksphinz:20200710234521p:plain
  • vtype.vta, vtype.vmaシステムレジスタフィールド

vtypeシステムレジスタには2つのレジスタフィールドが定義されている。vtype.vmavtype.vtaだ。これは「マスクされたレジスタフィールドをどのように取り扱うか」と言うことを規定しているレジスタフィールドだ。

マスクしているレジスタフィールドに対する計算結果をどのように扱うのかについては、2つの方針が考えられるだろう。例えば

vadd.vv v3,v4,v5,v0.t

という命令を実行した場合、書き込みレジスタv3においてマスクされたフィールドは、

  • マスクされているので固定値で更新する。
  • マスクされているので前の値を保持する。

という方針が考えられる。どちらにもメリットデメリットがあるのだが、問題となるのはアウトオブオーダ実行の時で、例えばベクトルレジスタ長が非常に長く、1ベクトルレジスタを複数のレジスタに分割してリネームしている場合、サブレジスタ全てがマスクにより無効化されているとき、そのレジスタに対する固定値書き込みをしてしまうと、本当はリネームしなくても良いのにリネームをしなければならなくなる。一方でマスクした値をキープすることになると、インオーダのプロセッサでは書き込みレジスタから一度データを読み取り、値を更新し(マスクする部分は値をキープし)書き込みなおすということで読み込みポートが1つ増えてしまう。まとめると以下のようなメリットデメリットがあるといえよう。

  • マスクされているので固定値で更新する。
    • リネームをしないプロセッサではレジスタ読み込みポートを節約することができる。
    • リネームをするプロセッサではマスクにより無効なレジスタでも常にリネームをする必要がある。
  • マスクされているので前の値を保持する。
    • リネームをしないプロセッサではレジスタの部分更新を許すため読み込みポートが増える。
    • リネームをするプロセッサではマスクにより無効なレジスタはリネームをせずに済む。

ということで、RISC-V Vector Extension 0.9ではこれを切り替えることができるオプションが用意されている。これがvtype.vmaである。

  • vtype.vma=1(Agnostic):マスクにより無効な要素はすべてのビットフィールドに1が書き込まれる、もしくは値を保持する。
  • vtype.vma=0(Undisturbed):マスクにより無効な要素は値を保持する。

で、実はこのオプションはハードウェアにより決め打ちすることは出来ない。仕様上は「Agnosic, Undisturbed」の両方を実装する必要がある。しかしリネームを行うプロセッサは、Agnosticの「もしくは」を除去し「値を保持する」に決め打ちすることができる。一方でリネームをしないプロセッサではこの設定自体を「無視する」と言うことが許されている。実はとってもあいまいなレジスタ仕様になっている(これはおそらくRISC-V Vector Extension 1.0で修正されると思われる)。

f:id:msyksphinz:20200711000552p:plain

という訳でvmaの役割が分かった。で、vtaも実は同じ役割を持っており、こちらはMaskedな要素に対する仕様ではなく、Tail要素に対する仕様となっている。

ベクトルレジスタに対する「Tail」というのは、vlレジスタにより設定されている現在のベクトル要素から、物理的に取りうる最大のベクトル要素数VLMAXまでの要素のことを言う。

例えば、VLEN=512, SEW=32, LMUL=1の場合は、物理的に1つのレジスタから512/32=16本の要素を取ることができる。これがVLMAXに相当する。そして実はvlレジスタはVLMAXよりも小さな値を設定することができる。これは半端な長さのベクトルを処理するための処置で、vlレジスタに設定されたベクトルの要素数と、物理限界であるVLMAXまでの間の要素のことをTailと呼んでいる。

f:id:msyksphinz:20200711001051p:plain

このTail要素に対してもvtype.vtaシステムレジスタにより取り扱いを決めることができる。これがvtype.vmavtype.vtaの役割だ。

f:id:msyksphinz:20200711001714p:plain