FPGA開発日記

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

RISC-Vの浮動小数点命令をISSに実装する

MIPS浮動小数点命令についても、大分実装が進んできたので、RISC-Vの実装を進めていこう。

RISC-Vにも単精度、倍精度の浮動小数点演算命令が定義されている。

Download - RISC-V

RISC-Vの浮動小数点命令をISSに実装する

ISSの実装についてはMIPSのそれと殆ど変わらない。

github.com

例えば32ビット単精度浮動小数点の加算命令は以下のように定義する。

void InstEnv::RISCV_INST_FADD_S (Word_t inst_hex)
{
    RegAddr_t rs1_addr = ExtractR1Field (inst_hex);
    RegAddr_t rs2_addr = ExtractR2Field (inst_hex);
    RegAddr_t rd_addr  = ExtractRDField (inst_hex);

    Word_t  rs1_val  = m_env->ReadFReg<Word_t> (rs1_addr);
    Word_t  rs2_val  = m_env->ReadFReg<Word_t> (rs2_addr);

    UWord_t fflags;
    Word_t res = InstOps::FloatAdd (rs1_val, rs2_val, &fflags);

    m_env->WriteFReg<Word_t> (rd_addr, res);
    m_env->CSRWrite (SYSREG_ADDR_FFLAGS, fflags);
}

CSRWrite()を使って、Softfloatの例外判定結果を書き込んでいる。このFloatAdd()関数は、softfloatを呼び出して浮動小数点演算を行い、例外結果をsoftfloat_exceptionFlagsという定数に返している。

Word_t InstOps::FloatAdd (Word_t op1, Word_t op2, uint32_t *fflags)
{
    float32_t f_op1, f_op2;
    f_op1.v = op1;
    f_op2.v = op2;

    float32_t f_res = f32_add(f_op1, f_op2);
    Word_t    res   = f_res.v;
    *fflags = softfloat_exceptionFlags;

    return res;
}

これをRISC-Vの定義する命令だけ記述した。まだ32ビットモードしか実装していなかったので、倍精度の命令は実装できていないが、まずはこんなところだろう。

浮動小数点命令をテストする

RISC-Vの実装をテストしてみよう。RISC-Vにはテストパタンであるricv_testsリポジトリが提供されている。

github.com

コンパイルしたfaddのテストパタンを実行してみよう。

./swimmer_riscv --binfile ~/riscv-tools/riscv-tests/isa/rv64uf-p-fadd --debug

まずはmcpuidを適切に指定する必要があった。mcpuidのBaseフィールドに適切な値を設定していないと、パタンの先頭でコけて停止してしまう。

f:id:msyksphinz:20160109011224p:plain

このレジスタを適切に設定してパタンを実行してみると、お、流れた!

...
        49 : [000002d4] 00052007 : flw        r00,r10,0x000        r10=>00001020 (00001020)=>40490fdb f00<=40490fdb
        50 : [000002d8] 00452087 : flw        r01,r10,0x004        r10=>00001020 (00001024)=>322bcc77 f01<=322bcc77
        51 : [000002dc] 00852107 : flw        r02,r10,0x008        r10=>00001020 (00001028)=>00000000 f02<=00000000
        52 : [000002e0] 00c52683 : lw         r13,r10,0x00c        r10=>00001020 (0000102c)=>40490fdb r13<=40490fdb
        53 : [000002e4] 001071d3 : fadd.s     r03,r00,r01          f00=>40490fdb f01=>322bcc77 f03<=40490fdb fflags<=00000001
        54 : [000002e8] e0018553 : fmv.x.s    r10,r03              f03=>40490fdb r10<=40490fdb
        55 : [000002ec] 001015f3 : csrrw      r11,0x001,r00        fflags=>00000001 r00=>00000000 fflags<=00000000 r11<=00000001
        56 : [000002f0] 00100613 : addi       r12,r00,0x001        r00=>00000000 r12<=00000001
        57 : [000002f4] 34d51c63 : bne        r10,r13,0x1a         r10=>40490fdb r13=>40490fdb
        58 : [000002f8] 34c59a63 : bne        r11,r12,0x1a         r11=>00000001 r12=>00000001
        59 : [000002fc] 0040006f : jal        r00,0x00400          pc<=00000300
        60 : [00000300] 00500e13 : addi       r28,r00,0x005        r00=>00000000 r28<=00000005
        61 : [00000304] 00001517 : auipc      r10,0x00001          r10<=00001304
        62 : [00000308] d2c50513 : addi       r10,r10,0xd2c        r10=>00001304 r10<=00001030
        63 : [0000030c] 00053007 : fld        r00,r10,0x000        r10=>00001030 (00001030)=>00000000 (00001034)=>40040000 f00<=00000000
        64 : [00000310] 00853087 : fld        r01,r10,0x008        r10=>00001030 (00001038)=>00000000 (0000103c)=>3ff00000 f01<=00000000
        65 : [00000314] 01053107 : fld        r02,r10,0x010        r10=>00001030 (00001040)=>00000000 (00001044)=>00000000 f02<=00000000
<Error: instruction is not decoded. [00000318]=01853683
ChangeMode from Supervisor to Machine
        67 : [00000140] 34202f73 : csrrs      r30,0x342,r00        r00=>00000000 mcause=>00000002 r30<=00000002
        68 : [00000144] fa0f5ee3 : bge        r30,r00,0x7d         r30=>00000002 r00=>00000000 pc<=00000100
...

演算命令を実行した後、整数レジスタに移動して、演算結果と例外結果(fflags)の結果を比較している。

しかし、どうやらこのパタンは単精度命令と倍精度命令が混在して含まれているらしく、倍精度のfadd.d命令の所でエラーを吐いてしまった。 これは、最終的に64ビットモードをサポートしてパタンを通す必要があるなあ。