FPGA開発日記

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

自作CPUにベクトル命令を追加する実装検討 (38. Widening / Narrowingについて考えを巡らせる)

RISC-Vのベクトル命令には、浮動小数点におけるWideningとNarrowingというものがある。

Wideningは、浮動小数点の演算実行時に、データ型を拡張して計算するものであり、一方でNarrowingは、データ型を縮小して計算する。 例えば、SEW=32(FP32)ならば、演算実行前(あるいは実行後)にデータ幅をFP64に拡張させてから実行する。 一方で、NarrowingはSEW=64ならば、演算実行前(あるいは実行後)にデータ幅をFP32に縮小する。

# Double-width result, two single-width sources: 2*SEW = SEW op SEW 
vwop.vv  vd, vs2, vs1, vm  # integer vector-vector      vd[i] = vs2[i] op vs1[i] 
vwop.vx  vd, vs2, rs1, vm  # integer vector-scalar      vd[i] = vs2[i] op x[rs1] 

# Double-width result, first source double-width, second source single-width: 2*SEW = 2*SEW op SEW 
vwop.wv  vd, vs2, vs1, vm  # integer vector-vector      vd[i] = vs2[i] op vs1[i] 
vwop.wx  vd, vs2, rs1, vm  # integer vector-scalar      vd[i] = vs2[i] op x[rs1]

つまり、入力するオペランドのサイズと出力するオペランドのサイズが違うため、レジスタのサイズに合わせてパイプラインの制御を調整する必要がある。結構面倒くさい。

// vfwadd.vv vd, vs2, vs1
VI_VFP_VV_LOOP_WIDE
({
  vd = f32_add(vs2, vs1);
},
{
  vd = f64_add(vs2, vs1);
})
// vfwadd.wv vd, vs2, vs1
VI_VFP_WV_LOOP_WIDE
({
  vd = f32_add(vs2, vs1);
},
{
  vd = f64_add(vs2, vs1);
})

つまり、LMUL=xで実行開始しても、レジスタの書き込みはLMUL=2xのつもりで書きこまなければならない。VLEN=512, DLEN=128の場合、パイプラインイメージとしては以下のようになるか? 命令の発行は、1サイクルずつ空けながら、2回レジスタに書き込む余裕を持たせる必要がありそうだ。

1オペランドだけLMUL=2xのつもりでレジスタを読まなければならないのも、同じようなパイプラインの制御で行けるかな。