FPGA開発日記

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

RISC-Vベクトル拡張仕様書 v1.0 を読み直す (19. 固定小数点演算命令)

RISC-Vベクトル拡張仕様書の読み直し。次は固定小数点命令など。

github.com

github.com


12. ベクトル固定小数点算術演算命令

前述の整数演算命令群を拡張し、固定小数点演算がサポートされています。

固定小数点数とは、暗黙の分母を持つ分数の分子として解釈される2の補数の符号付きまたは符号なしの整数です。 固定小数点命令は分子に適用されることを意図しており、分母を管理するのはソフトウェアの責任です。 Nビットの要素には、-2N-1…​+2N-1-1の範囲の2の補数の符号付き整数と、0…​+2N-1-1の範囲の符号なし整数を格納できます。 固定小数点命令は、スケーリングと丸めをサポートすることで狭いオペランドの精度を維持し、 結果を出力フォーマット範囲に飽和させることでオーバーフローを処理することができます。

Note: 上述の幅拡張整数演算は、オーバーフローを回避するためにも使用できます。

12.1. ベクトル単一幅飽和加算と飽和減算

符号付き整数と符号なし整数の両方に対して、飽和形式の整数の加算と減算が提供されます。 結果が出力先をオーバーフローする場合、結果は最も近い表現可能な値で置き換えられ、 vxsat ビットが設定されます。

# 符号なし整数の飽和加算
vsaddu.vv vd, vs2, vs1, vm   # ベクトル-ベクトル
vsaddu.vx vd, vs2, rs1, vm   # ベクトル-スカラ
vsaddu.vi vd, vs2, imm, vm   # ベクトル-即値

# 符号付き整数の飽和加算
vsadd.vv vd, vs2, vs1, vm   # ベクトル-ベクトル
vsadd.vx vd, vs2, rs1, vm   # ベクトル-スカラ
vsadd.vi vd, vs2, imm, vm   # ベクトル-即値

# 符号付き整数の飽和減算
vssubu.vv vd, vs2, vs1, vm   # ベクトル-ベクトル
vssubu.vx vd, vs2, rs1, vm   # ベクトル-スカラ

# 符号付き整数の飽和減算
vssub.vv vd, vs2, vs1, vm   # ベクトル-ベクトル
vssub.vx vd, vs2, rs1, vm   # ベクトル-スカラ

12.2. ベクトル単一幅平均加算と平均減算命令

平均化された加算・減算命令は、結果を1ビット右シフトし、 vxrm の設定に従って結果を丸める。 符号なしと符号ありのバージョンがあります。 vaaddu と vaadd では、結果にオーバーフローがあってはなりません。 vasub と vasubu では、オーバーフローは無視され、結果は折り返されます。

Note: vasub では、rnu や rne の丸め方で最大の数から最小の数を引くときにのみオーバーフローが発生します。

# 平均加算

# 符号なし整数の平均加算
vaaddu.vv vd, vs2, vs1, vm   # roundoff_unsigned(vs2[i] + vs1[i], 1)
vaaddu.vx vd, vs2, rs1, vm   # roundoff_unsigned(vs2[i] + x[rs1], 1)

# 符号付き整数の整数加算
vaadd.vv vd, vs2, vs1, vm   # roundoff_signed(vs2[i] + vs1[i], 1)
vaadd.vx vd, vs2, rs1, vm   # roundoff_signed(vs2[i] + x[rs1], 1)

# 平均減算

# 符号なし整数の平均減算
vasubu.vv vd, vs2, vs1, vm   # roundoff_unsigned(vs2[i] - vs1[i], 1)
vasubu.vx vd, vs2, rs1, vm   # roundoff_unsigned(vs2[i] - x[rs1], 1)

# 符号付き整数の平均減算
vasub.vv vd, vs2, vs1, vm   # roundoff_signed(vs2[i] - vs1[i], 1)
vasub.vx vd, vs2, rs1, vm   # roundoff_signed(vs2[i] - x[rs1], 1)

12.3. 丸めと飽和を用いたベクトル単一幅分数乗算

符号付き分数乗算命令は、2つのSEW入力の2*SEW積を生成し、その結果をSEW-1ビットだけ右にシフトし、これらのビットを vxrm に従って丸めた後、SEWビットに収まるように結果を飽和させます。 結果が飽和した場合は、 vxsat ビットがセットされます。

# 符号付き飽和丸め分数乗算
# 丸め演算については、vxrmの説明を参照のこと
vsmul.vv vd, vs2, vs1, vm  # vd[i] = clip(roundoff_signed(vs2[i]*vs1[i], SEW-1))
vsmul.vx vd, vs2, rs1, vm  # vd[i] = clip(roundoff_signed(vs2[i]*x[rs1], SEW-1))

Note: 2つのNビット符号付き数値を乗算する場合、最大の大きさは-2N-1 * -2N-1で得られ、 結果は+22N-2となり、2Nビットで保持する場合、符号ビットは1つ(ゼロ)となります。 他のすべての製品は、2Nビットで2つの符号ビットを持ちます。 N個の結果ビットでより高い精度を維持するために、製品はNよりも1ビット少ない数だけ右にシフトされ、 最大の大きさの結果は飽和しますが、他のすべての製品では結果の精度が1ビット増加します。 Note: 一方の入力が符号なしの場合には、SEWの上位ビットをすべて保持し、飽和させる必要がないため、同等の分数乗算は提供していません。 この操作は、丸めが単なる切り捨て(rdn)である場合には、 vmulhu および vmulhsu 命令によって部分的にカバーされます。

12.3.1. ベクトル単一幅スケーリングシフト命令

これらの命令は、入力値を右にシフトし、シフトしたビットを vxrm に従って丸めます。 スケーリングの右シフトには、ゼロ拡張型 (vssrl) と符号拡張型 (vssra) があります。 ベクトルまたはスカラのシフト量の値の下位lg2(SEW)ビットが使用され、シフト量の即値はゼロ拡張されます。

 # 論理スケーリング右シフト
 vssrl.vv vd, vs2, vs1, vm   # vd[i] = roundoff_unsigned(vs2[i], vs1[i])
 vssrl.vx vd, vs2, rs1, vm   # vd[i] = roundoff_unsigned(vs2[i], x[rs1])
 vssrl.vi vd, vs2, uimm, vm  # vd[i] = roundoff_unsigned(vs2[i], uimm)

 # 算術スケーリング右シフト
 vssra.vv vd, vs2, vs1, vm   # vd[i] = roundoff_signed(vs2[i],vs1[i])
 vssra.vx vd, vs2, rs1, vm   # vd[i] = roundoff_signed(vs2[i], x[rs1])
 vssra.vi vd, vs2, uimm, vm  # vd[i] = roundoff_signed(vs2[i], uimm)

12.4. ベクトル固定小数点幅縮小クリップ命令

vnclip 命令は、固定小数点の値をより狭い出力先に詰めるために使用されます。 この命令は、最終的な出力形式への丸め、スケーリング、および飽和をサポートします。

2番目の引数(ベクトル要素、スカラー値、即値)は、狭義のシフト命令のようにソースを右シフトする量を与え、スケーリングを行います。 ベクトルまたはスカラのシフト量の値の下位lg2(2*SEW)ビットが使用されます(例:SEW=64ビットからSEW=32ビットへの狭帯域化操作の場合は下位6ビット)。 即値形式は、シフト量の即値オペランドをゼロ拡張します。

# 符号なし幅縮小クリップ命令
#                                SEW                            2*SEW   SEW
 vnclipu.wv vd, vs2, vs1, vm  # vd[i] = clip(roundoff_unsigned(vs2[i], vs1[i]))
 vnclipu.wx vd, vs2, rs1, vm  # vd[i] = clip(roundoff_unsigned(vs2[i], x[rs1]))
 vnclipu.wi vd, vs2, uimm, vm # vd[i] = clip(roundoff_unsigned(vs2[i], uimm))

# 符号付き幅縮小クリップ
 vnclip.wv vd, vs2, vs1, vm   # vd[i] = clip(roundoff_signed(vs2[i], vs1[i]))
 vnclip.wx vd, vs2, rs1, vm   # vd[i] = clip(roundoff_signed(vs2[i], x[rs1]))
 vnclip.wi vd, vs2, uimm, vm  # vd[i] = clip(roundoff_signed(vs2[i], uimm))

vnclipu/vnclip では、丸め方は vxrm CSR で指定します。 丸めは、書き込みレジスタの最下位ビットを中心に、飽和演算の前に行われます。

vnclipu では、シフトされた丸められたソース値は符号なし整数として扱われ、 その結果が符号なし整数として見た書き込みレジスタをオーバーフローする場合は飽和します。

Note: 符号付きの値を符号なしの出力先に飽和させることができる単一の命令はありません。 vxsat の値を設定する必要がない場合は、まず vmax を使って0に対する最大値を実行して負の数を取り除き、 次に vnclipu を使って結果の符号なしの値を出力先にクリップする、2つのベクトル命令列を使用できます。 SEWを変更するには、この2つの命令の間に、 vsetvli が必要です。 vnclip では、丸められたシフト元の値を符号付き整数として扱い、その結果が符号付き整数として見たときに 書き込みレジスタをオーバーフローさせるようであれば飽和を行います。

いずれかの書き込みレジスタの要素が飽和した場合、 vxsat レジスタに vxsat ビットが設定されます。