FPGA開発日記

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

自作RISC-Vコアにおける浮動小数点命令サポートの実装

浮動小数点命令をサポートするためには、まずはレジスタファイル、そして検証環境の更新が必要だ。

まず、SpikeにおけるFPU命令のトレースログの取り扱いについては、浮動小数点命令レジスタへの書き込みが行われると、レジスタの種類のビットが変更される。

  • spike_dpi/riscv-isa-sim/riscv/decode.h
 # define WRITE_FREG(reg, value) ({ \
     freg_t wdata = freg(value); /* value may have side effects */ \
     STATE.log_reg_write[((reg) << 4) | 1] = wdata; \
     DO_WRITE_FREG(reg, wdata); \
   })

log_reg_writeの書き込みは、浮動小数点演算の場合には下位ビットに1が設定される。これを使って判定する。

まずはISSとRTLで書き込みレジスタタイプが異なればエラーを出力します。

   if (rtl_wr_valid &&
       (iss_wr_type == 0 || iss_wr_type == 1) &&
       (rtl_wr_type == 0 || rtl_wr_type == 1) &&
       iss_wr_type != rtl_wr_type) {
     fprintf(compare_log_fp, "==========================================\n");
     fprintf(compare_log_fp, "RTL/ISS Write Register Type different.\n");
     fprintf(compare_log_fp, "ISS = %s, RTL = %s\n", iss_wr_type == 0 ? "GPR" :
             iss_wr_type == 1 ? "FPR" : "Others",
             rtl_wr_type == 0 ? "GPR" :
             iss_wr_type == 1 ? "FPR" : "Others");
     fprintf(compare_log_fp, "==========================================\n");
     stop_sim(100);
   }

FPRレジスタ書き込み命令であれば、FPRレジスタ同士を比較して、エラーがあれば出力する。

   } else if (rtl_wr_valid && iss_wr_type == 1) { // FPR write
     int64_t iss_wr_val = p->get_state()->FPR[rtl_wr_gpr_addr].v[0];
     if (!is_equal_xlen(iss_wr_val, rtl_wr_val)) {
       fprintf(compare_log_fp, "==========================================\n");
       fprintf(compare_log_fp, "Wrong FPR[%02d](%d): RTL = %0*llx, ISS = %0*lx\n",
               rtl_wr_gpr_addr, rtl_wr_gpr_rnid,
               g_rv_xlen / 4, rtl_wr_val,
               g_rv_xlen / 4, iss_wr_val);
       fprintf(compare_log_fp, "==========================================\n");
       fail_count ++;
       if (fail_count >= fail_max) {
         stop_sim(100);
       }
       return;
     } else {
       fprintf(compare_log_fp, "FPR[%02d](%d) <= %0*llx\n", rtl_wr_gpr_addr, rtl_wr_gpr_rnid, g_rv_xlen / 4, rtl_wr_val);
     }
   }

これで、まずはFMV.D.X命令の動作を確認する。FMV.D.X命令は、整数レジスタのデータを、データ型変換することなく、そのまま浮動小数レジスタに転送する命令だ。

f:id:msyksphinz:20220213231047p:plain
RISC-V命令仕様書より引用。データ転送系命令の一部
make rv64_tiny && ./msrh_tb_rv64_tiny-debug -d -e ../tests/riscv-tests/isa/rv64ud-p-move -o rv64ud-p-move.tiny.log | spike-dasm

あれ、リネーム機能のアサーションで落ちてしまった。

CSR_MCYCLE written 00000000
CSR_MCYCLE written 00000000
[10254] %Error: msrh_rename.sv:495: Assertion failed in TOP.msrh_tb.u_msrh_tile_wrapper.u_msrh_tile.u_msrh_int_rename.unnamedblk4.list_check1_loop.unnamedblk5.list_check2_loop: Index  55( 1, 23) and  75( 2, 11) are same ID:   1

%Error: ../src/../src/msrh_rename.sv:495: Verilog $stop

命令自体は何となく動いているように見える。デバッグしていく。

GPR[11](65) <= 000091a2b3c4d5e7
2555 : 77 : PC=[000000008000019c] (U,03,01) 00d59593 slli    a1, a1, 13
GPR[11](6) <= 123456789abce000
2556 : 78 : PC=[00000000800001a0] (U,04,01) ef058593 addi    a1, a1, -272
GPR[11](1) <= 123456789abcdef0
2561 : 79 : PC=[00000000800001a4] (U,05,01) 00000613 li      a2, 0
GPR[12](9) <= 0000000000000000
2561 : 80 : PC=[00000000800001a8] (U,05,02) f20580d3 fmv.d.x ft1, a1
FPR[01](64) <= 123456789abcdef0
2562 : 81 : PC=[00000000800001ac] (U,06,01) f2060153 fmv.d.x ft2, a2
FPR[02](32) <= 0000000000000000