一人一党党

一人一人の、一人一人による、一人一人のための政治制度を!

RISC-Vは高速な命令セットとして設計し損ねている

RISC-V
http://riscv.org/
は高速なCPU向けの命令セットを謳っていてる。

例えば、即値のデコード。
RISCなので各命令の位置はアラインメントされていて、ジャンプ先アドレスの最下位ビット(least significant bit, 以下lsb)は0であることが分かりきっている。
あるいは、x86のようにバイト単位で命令長が変わるプロセッサでも、データアクセスについては最下位ビットを0にする方が高速に動作できる。
このため、これら普通のプロセッサでは、即値を取り出した後、必要に応じてシフト演算を掛ける。
しかしRISC-Vの場合は、lsbだけ即値の最上位にシフトして、残りのビットはシフトせずに出力するという、ある種のローテート演算でlsbをクリアする。
シフト演算では、殆どの入力ビットに変換後のシフト位置への配線を用意しなければならず、殆どの出力ビットに入力ビットを選択するためのマルチプレクサが必要になる。
しかしローテート演算なら、lsb以外の入力ビットには一本しか配線しなくていいし、ローテートさせるビット以外は、配線が一本しか来ないから、殆どの出力ビットにはマルチプレクサは要らない。
配線の接続数(fan-out)が増えれば、流さねばならない電流も増えるし、マルチプレクサが間にあると、電気信号の伝達が大きく遅れるし、電力も食う。
逆に、fan-outやマルチプレクサが少なければ、消費電力が減って電気信号の伝達が速くなるから、高速なプロセッサが出来上がる仕組みだ。
fan-outとマルチプレクサ数が少なくなるように、命令フォーマットを設計したとRISC-Vは謳っている。

しかしその割には、fan-outやマルチプレクサの多いビットが、RISC-Vの命令セットにはある。
命令セットRV32Iの場合、
*命令20ビット目(rs2のlsb)のfan-outだけ3本
*即値11ビット目(U-type系のlsb直下)のマルチプレクサだけ3個
局所的に、fan-out・マルチプレクサの多いビットがある。
即値11ビット目のマルチプレクサ数については、下記の「蛇足」の最後でも触れるが、簡単な解決法を私はみつけていない。
しかし命令20ビット目については、
*U-typeでの移動位置と同じ位置へUJ-typeの場合でも出力
*UJ-typeでの代わりの出力には、fan-outが1本しかない命令19ビット目を当てる
方法があり、最大fan-outを3本から2本へ減らすことができる。

回路規模でみれば、32ビット中の1ビットくらい大したことではない。
しかし速度の点で見れば、デコードの最も遅いビットが、全体の動作速度を決定する。
RISC-Vの設計者達は、この点を見落としていたのか?


蛇足 -- RISC-VのRV32Iを参考にした16ビット命令セット --

16ビット命令と32ビット命令の組み合わせでは、CISCを越えるコード密度がでるそうだ。
しかし本家RISC-Vの16ビット命令拡張は、srcレジスタ破壊の避けられない2オペランド方式。
コピー命令が必要になるので、仮想マシンインタプリタ静的単一代入コンパイラに優しくない。
レジスタコピー命令が実質不要になる3オペランドが欲しい。

*RISC-Vに倣って、拡張命令(32ビットとか)のため最下位2ビットは00,01,10に制限
*入力レジスタ(二個)と出力レジスタ
*汎用レジスタは7個(ゼロレジスタで8個)
*即値の符号ビットは、オペコードと共有する
*物理回路で実装するときにマルチプレクサなどを節約する即値フォーマット。
*拡張命令ビット、符号ビット、レジスタ3個のフィールド位置は固定。

命令長が伸びる原因で最大のものは即値。
オペランド数はほぼ固定。
命令数やレジスタ数は2の対数でしか増えない。
即値=レジスタ幅は2のベキ乗で増える。
逆に言えば、即値を考慮しなければ命令長を縮めることができる。
RV64I拡張では命令長は32ビットのままで64ビット即値を考慮していない。
x86が示すように、汎用レジスタが7個あれば現代的なソフトでも十分な効率で動作する。
レジスタ数が7個なら、3オペランド分フィールドを占有されても7ビットの余裕があり、命令拡張スペースを除けば、96個の命令が使える。
RV32I 40個(SCALL関連8個はまとめる)
負数も使う -> 23個 -> 符号ビットで2倍の46個
負数なし(シフト関連) -> 3個
即値無し -> 13個
合計 62個
なので、RV32Iに1対1対応したものができる。
さらに、あまりにも即値が小さいので、3レジスタ即値も追加。

jalrまで2バイト境界処理されていたら、最大fan-outが3になってた。

f-d c-a 9-7 6 0
rs1 rs2 rde R-type
rs1 mmm rde I-type
rs1 rs2 mmm S-type(store系)
rs1 rs2 mmb SB-type(比較分岐系)
mmm mmm rde 2レジスタ即値
mmm mmb rde UB-type
mmm bbb rde U-type(lui,auipcなど、上位ビット操作)
mmb bbb mmb 3レジスタjmp
mmm bbb mmm 3レジスタ即値(出力レジスタのデコードが特殊なので、推奨しない)

fan-out数
112 222 112

sss sss sss 222 I-type
sss sss sss ddd S-type
sss sss ssd dd0 SB-type
sss sss 111 222 2レジスタ即値
sss ss2 111 220 UB-type
sss 222 111 000 U-type
ss1 222 11d dd0 3レジスタjmp
sss 222 111 ddd 3レジスタ即値

マルチプレクサ数
001 111 112 222

U-typeのシフト量を抑えたので、最大fan-out数だけでなく最大マルチプレクサ数でも、RISC-Vより少なくなった。
本来ならRISC-Vでも、同様の方法で最大マルチプレクサ数を削減できる。
しかし31ビットではなく32ビットの即値に、RISC-Vは拘った。

16ビット命令にも拘らずレジスタを32個扱えたり、現実のプログラム用途に合わせて命令を選ぶなど、RISC-V本家の16ビット拡張の方が実用的かもしれない。
しかしこちらは、RV32Iがそうであるように、単独で動作可能な基本命令セットだ。
誰かFPGAとかで実装したら、本当に高速なプロセッサになったか、私に知らせてほしい。