RISC-Vを目指す(2)
RISC-V命令セットにしてみたらハンドアセンブルで命令を並べるのが大変になってしまったので、非常に雑にアセンブラを作ってみた。これもずっと前に作ったx86アセンブラを持ってきて書き直したものである。RISC-Vアセンブラ · GitHub
このような感じにシミュレータのコードに埋め込んで使う。
# 8アドレスぶんの命令 rom.d = RISCVASM.asm do addi r1, r0, 0 addi r2, r0, 0 addi r3, r0, 1 label :fibonacci add r1, r0, r2 add r2, r0, r3 add r3, r1, r2 jal r0, :fibonacci nop end.map{|t|_to_pin(t, vcc, gnd)}.reverse
jal命令追加
jalrはレジスタ間接絶対アドレスジャンプなのだと思うのだが、レジスタ間接のためにアセンブラでラベル指定ができない。できないわけじゃないけどちょっと微妙なので、相対ジャンプであるjal命令を実装してみた。相対ジャンプはPCの値と即値を加算してジャンプ先アドレスを求める必要があり、adderの入力パターンが増えてややこしくなる。
# 32bit全加算器 adder.d = [_if(insn_jal, pc.o, regf.o0), _if(insn_jal, [insn_bit_imm20_1[0]]*11 + insn_bit_imm20_1 + [gnd], # jal命令 _if(insn_add, regf.o1, # add命令 [insn_bit_imm11_0[0]]*20 + insn_bit_imm11_0 # それ以外 )) ] adder.x = gnd
このへんはもうちょっと書きやすくする仕掛けが欲しいところである。また、jal命令の即値は順番が単純じゃなく、これまた非常にややこしい。
insn_bit_imm20_1 = [insn[0]] + insn[12..19] + [insn[11]] + insn[1..10]
なんでこうなっているのかというと、他の命令の配置となるべく同じ位置に同じ線を配置するためであり、例えば即値の[10:5]はI、S、B、Jの4タイプで共通の位置となっている。このおかげで命令によってピンの意味が変わることが少なく、マルチプレクサを置く必要が無い、という話だ。
jal命令の即値は20bitだが、実際には21〜1の範囲が命令内にエンコードされている。最下位のビットは常に0(偶数アドレスのみ)で、4の倍数にしていないのは16bit命令セットを扱うことを考えているからかもしれない。最上位bitを符号として扱うことで±1MBの相対ジャンプができる。
RISC-Vの命令の即値は基本的に全て符号付である。addiは即値を足す命令だが、subiは無い。2の補数と足してくれ、と。符号bitは常に命令の最上位に位置するように作られている。随所に回路が簡単になる工夫が詰め込まれているのだが、俺はいまのところそれを有効に活用できている気がしない。