開発日記

Erlangをダラダラ書きます。

RISC-V 32bit M拡張(整数乗除算拡張命令)

概要

R形式

31 - 25 24 - 20 19 - 15 14 - 12 11 - 7 6 - 0
funct7 rs2 rs1 funct3 rd オペコード

オペコードで命令形式を判別

funct3でM拡張命令を判別(funct7は全て同じ)

フォーマット

命令 rd, rs1, rs2

注意点

verilogでは明示しない限り,値はunsignedとして扱われる.

算術右シフトは「符号ありの値」と「>>>」を用いて実現する.

div, rem では0除算を考慮

各命令

mul

31 - 27 26 - 25 24 - 20 19 - 15 14 - 12 11 - 7 6 - 2 1 - 0
0000 01 rs2 rs1 000 rd 01100 11

rs1とrs2の値を読み出し,その積の下位32bitをrd番のレジスタに書き込む

x[rd] = $signed(x[rs1]) * $signed(x[rs2]);

mulh

31 - 27 26 - 25 24 - 20 19 - 15 14 - 12 11 - 7 6 - 2 1 - 0
0000 01 rs2 rs1 001 rd 01100 11

rs1とrs2を符号あり整数として解釈し,結果を符号あり整数として計算.

計算結果の上位32bitだけをレジスタに格納.

算術右シフトを使用する.

x[rd] = $signed($signed(x[rs1]) * $signed(x[rs2])) >>> 32;

mulhsu

31 - 27 26 - 25 24 - 20 19 - 15 14 - 12 11 - 7 6 - 2 1 - 0
0000 01 rs2 rs1 010 rd 01100 11

rs1を符号あり整数,rs2を符号なし整数として解釈し,結果を符号あり整数として計算.

計算結果の上位32bitだけをレジスタに格納.

算術右シフトを使用する.

x[rd] = $signed(($signed(x[rs1]) * $signed({1'b0, x[rs2]})) >>> 32;

mulhu

31 - 27 26 - 25 24 - 20 19 - 15 14 - 12 11 - 7 6 - 2 1 - 0
0000 01 rs2 rs1 011 rd 01100 11

rs1とrs2を符号なし整数として解釈し,結果を符号なし整数として計算.

計算結果の上位32bitだけをレジスタに格納.

x[rd] = (x[rs1] * x[rs2]) >> 32;

div

31 - 27 26 - 25 24 - 20 19 - 15 14 - 12 11 - 7 6 - 2 1 - 0
0000 01 rs2 rs1 100 rd 01100 11

rs1とrs2は符号あり整数として解釈し,結果を符号あり整数として計算.

求めるべき商は,数学的な商ではなく,答えを実数で求めた後小数点以下を切り捨てたもの.(0への丸め)

ゼロ除算(rs2が0):-1.

オーバーフロー(rs1が−2^{31}かつrs2が-1の時,数学的な結果は2^{31}だが表現できない):-2^{31}

x[rd] = (x[rs2] == 32'b0) ? 32'hffff_ffff :
      ((x[rs1] == 32'h8000_0000) && (x[rs2] == 32'hffff_ffff)) ? 32'h8000_0000 :
      $signed($signed(x[rs1]) / $signed(x[rs2]));

divu

31 - 27 26 - 25 24 - 20 19 - 15 14 - 12 11 - 7 6 - 2 1 - 0
0000 01 rs2 rs1 101 rd 01100 11

rs1とrs2は符号なし整数として解釈し,結果を符号なし整数として計算.

求めるべき商は,数学的な商ではなく,答えを実数で求めた後小数点以下を切り捨てたもの.(0への丸め)

ゼロ除算(rs2が0):2^{32}-1.

x[rd] = (x[rs2] == 32'b0) ? 32'hffff_ffff :
        (x[rs1] / x[rs2]);

rem

31 - 27 26 - 25 24 - 20 19 - 15 14 - 12 11 - 7 6 - 2 1 - 0
0000 01 rs2 rs1 110 rd 01100 11

rs1とrs2は符号あり整数として解釈し,結果を符号あり整数として計算.

求めるべき商は,数学的な剰余ではなく,符号が被除数と同じ剰余.(rs1とrs2の絶対値をとってから剰余を計算した後,rs1と同じ符号にすればよい)

ゼロ除算(rs2が0):rs1

オーバーフロー(rs1が2^{31}かつrs2が-1の時):0

x[rd] = (x[rs2] == 32'b0) ? x[rs1] :
        ((x[rs1] == 32'h8000_0000) && (x[rs2] == 32'hffff_ffff)) ? 32'h0 :
        $signed($signed(x[rs1]) % $signed(x[rs2]));

remu

31 - 27 26 - 25 24 - 20 19 - 15 14 - 12 11 - 7 6 - 2 1 - 0
0000 01 rs2 rs1 111 rd 01100 11

rs1とrs2は符号なし整数として解釈し,結果を符号なし整数として計算.

ゼロ除算(rs2が0):rs1

x[rd] = (x[rs2] == 32'b0) ? x[rs1] :
        (x[rs1] % x[rs2]);

参考