diff --git a/src/cpu/riscv_fpu.c b/src/cpu/riscv_fpu.c index aa2daa341..5d9491f45 100644 --- a/src/cpu/riscv_fpu.c +++ b/src/cpu/riscv_fpu.c @@ -126,6 +126,7 @@ static slow_path void riscv_emulate_f_opc_op_impl(rvvm_hart_t* vm, const uint32_ const uint32_t rm = bit_ext_u32(insn, 12, 3); const size_t rs1 = bit_ext_u32(insn, 15, 5); const size_t rs2 = bit_ext_u32(insn, 20, 5); + const uint32_t eff_rm = rm == RM_DYN ? bit_cut(vm->csr.fcsr, 5, 3) : rm; if (likely(riscv_fpu_is_enabled(vm))) { @@ -184,8 +185,8 @@ static slow_path void riscv_emulate_f_opc_op_impl(rvvm_hart_t* vm, const uint32_ riscv_write_s(vm, rds, fpu_fcvt_f64_to_f32(riscv_view_d(vm, rs1))); return; case 0x04: // fround.s (Zfa) - case 0x05: // TODO: froundx.s (Zfa) - riscv_emit_s(vm, rds, fpu_fcvt_i64_to_f32(fpu_round_f32_to_i64(riscv_read_s(vm, rs1), rm))); + case 0x05: // froundnx.s (Zfa) + riscv_emit_s(vm, rds, fpu_round_to_integral32(riscv_read_s(vm, rs1), eff_rm, rs2 == 0x05)); return; } break; @@ -195,8 +196,8 @@ static slow_path void riscv_emulate_f_opc_op_impl(rvvm_hart_t* vm, const uint32_ riscv_write_d(vm, rds, fpu_fcvt_f32_to_f64(riscv_read_s(vm, rs1))); return; case 0x04: // fround.s (Zfa) - case 0x05: // TODO: froundx.s (Zfa) - riscv_emit_d(vm, rds, fpu_fcvt_i64_to_f64(fpu_round_f64_to_i64(riscv_view_d(vm, rs1), rm))); + case 0x05: // froundnx.d (Zfa) + riscv_emit_d(vm, rds, fpu_round_to_integral64(riscv_view_d(vm, rs1), eff_rm, rs2 == 0x05)); return; } break; diff --git a/src/util/fpu_lib.h b/src/util/fpu_lib.h index 6541da22a..7a9650c0a 100644 --- a/src/util/fpu_lib.h +++ b/src/util/fpu_lib.h @@ -1753,6 +1753,36 @@ static forceinline int64_t fpu_round_f64_to_i64(fpu_f64_t d, uint32_t mode) return ret; } +static forceinline fpu_f32_t fpu_round_to_integral32(fpu_f32_t f, uint32_t mode, bool set_inexact) +{ + if (fpu_is_nan32_soft(f)) { + if (fpu_is_snan32_soft(f)) { + fpu_raise_invalid(); + } + return fpu_bit_u32_to_f32(FPU_LIB_FP32_CANONICAL_NAN); + } + fpu_f32_t ret = fpu_round_f32_internal(f, mode); + if (set_inexact && !fpu_is_bit_equal32(f, ret)) { + fpu_raise_inexact(); + } + return ret; +} + +static forceinline fpu_f64_t fpu_round_to_integral64(fpu_f64_t d, uint32_t mode, bool set_inexact) +{ + if (fpu_is_nan64_soft(d)) { + if (fpu_is_snan64_soft(d)) { + fpu_raise_invalid(); + } + return fpu_bit_u64_to_f64(FPU_LIB_FP64_CANONICAL_NAN); + } + fpu_f64_t ret = fpu_round_f64_internal(d, mode); + if (set_inexact && !fpu_is_bit_equal64(d, ret)) { + fpu_raise_inexact(); + } + return ret; +} + /* * IEEE 754 Signaling Comparisons *