FPGA開発日記

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

RISC-VのFPU命令がIllegal命令例外を発生した場合に何を確認すべきか

まあ自分用のメモというか、失敗記録なのだけれども。

例えば、以下のfcvt命令が急に命令例外を出した。SpikeのConfigurationはRV64GCにしているので間違いない。どこを確認すべきか?

core   0: 3 0x0000000080000e52 (0x20278bd3) f23 0xffffffff5f800000
core   0: 0x0000000080000e60 (0xc0360753) fcvt.lu.s a4, fa2
core   0: 0x0000000080000e64 (0x401df653) fcvt.s.d fa2, fs11
core   0: 3 0x0000000080000e64 (0x401df653) f12 0xffffffff5f000000
core   0: 0x0000000080000e7a (0x04912a27) fsw     fs1, 84(sp)
core   0: 0x0000000080000e82 (0xc204f4d3) fcvt.w.d s1, fs1
core   0: 0x0000000080000e86 (0xd027c553) fcvt.s.l fa0, a5
core   0: 3 0x0000000080000e86 (0xd027c553) f10 0xffffffff00000000
core   0: 0x0000000080000e8c (0x00235073) csrwi   frm, 6
core   0: 0x0000000080000e90 (0xf20f04d3) fmv.d.x fs1, t5
core   0: 3 0x0000000080000e90 (0xf20f04d3) f9  0x5cbd8fb1fff03836
core   0: 0x0000000080000e94 (0xf20404d3) fmv.d.x fs1, s0
core   0: 3 0x0000000080000e94 (0xf20404d3) f9  0x0000000000000084
core   0: 0x0000000080000ed4 (0xc234f553) fcvt.lu.d a0, fs1
core   0: exception trap_illegal_instruction, epc 0x0000000080000ed4
core   0: >>>>  custom_trap_handler
core   0: 0x0000000080000ed8 (0xe0061753) fclass.s a4, fa2
core   0: 0x0000000080000ee8 (0x000025e2) c.fldsp fa1, 24(sp)
core   0: 3 0x0000000080000ee8 (0x25e2) f11 0x48794d674b7a120a mem 0x00000000800939d0
core   0: 0x0000000080000eea (0xd0342453) fcvt.s.lu fs0, s0

まず大前提。RISC-VのFPU命令は演算結果に基づく例外は発生しない。例外結果はすべてFFLAGSに格納され、演算後に確認することになる。 したがって、演算結果に基づいてIllegal命令例外を発生することはない。

  • MISAレジスタの確認。基本的にMISAレジスタの値はRead-onlyにすることが多いと思うが、F/Dビットなどが書き換え可能な場合は誤ってDisableにしていないか確認。今回のケースではそれは当てはまらない。
  • mstatus.FSレジスタの確認。これはFPUの状態を管理するもので、コンテキスト退避の高速化を図るためのもの。演算実行前にCleanにしておく必要がある。これがInitのままだとFPU命令はIllegal命令例外を発生する。今回のケースではこれは当てはまらない。

正解は、frmレジスタの設定。frmはRounding-Modeの設定で、6はFuture Useで予約されている。これに設定した場合Illegal命令例外が発生する。

core   0: 0x0000000080000e8c (0x00235073) csrwi   frm, 6

これは、命令エンコーディングの中(12-14ビット目)にも埋め込まれているし、Dynamicモード (命令内エンコーディング=111)の場合はfrmレジスタを見る必要がある。

この表だと、frm=5/6/7が予約状態である。

で、さらに話がややこしくなるのが、このfrmレジスタに影響を受けるのがFPU命令によって異なるということ。詳細はマニュアルを読むべきなのだが、どのめいれいがfrmに影響されて例外が発生するのかは表にまとめてある。たとえば、fadd.s命令はfrmに影響さるが、fclass.s命令はfrmに影響されない。

つまり、正解は、fcvt命令が丸目モードをDynamicモードで実行しており、かつfrmレジスタが6(Reserved)だったので、Illegal命令例外を発生した、が正しい(、と思う)。

core   0: 0x0000000080000ed4 (0xc234f553) fcvt.lu.d a0, fs1
core   0: exception trap_illegal_instruction, epc 0x0000000080000ed4
core   0: >>>>  custom_trap_handler

というわけでしばらく悩んでしまった。