まあ自分用のメモというか、失敗記録なのだけれども。
例えば、以下の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
というわけでしばらく悩んでしまった。