For scalar float instruction, round mode is encoded in instruction, so fp_status is updating dynamiclly.
For vector float instruction, round mode is always frm, so update fp_status when frm changes is enough. Signed-off-by: LIU Zhiwei <zhiwei_...@c-sky.com> --- target/riscv/csr.c | 7 +++++++ target/riscv/fpu_helper.c | 19 ++++++++++++++----- target/riscv/internals.h | 3 +++ 3 files changed, 24 insertions(+), 5 deletions(-) diff --git a/target/riscv/csr.c b/target/riscv/csr.c index d71c49dfff..438093152b 100644 --- a/target/riscv/csr.c +++ b/target/riscv/csr.c @@ -22,6 +22,7 @@ #include "cpu.h" #include "qemu/main-loop.h" #include "exec/exec-all.h" +#include "internals.h" /* CSR function table */ static riscv_csr_operations csr_ops[]; @@ -174,6 +175,9 @@ static int write_frm(CPURISCVState *env, int csrno, target_ulong val) env->mstatus |= MSTATUS_FS; #endif env->frm = val & (FSR_RD >> FSR_RD_SHIFT); + if (!riscv_cpu_set_rounding_mode(env, env->frm)) { + return -1; + } return 0; } @@ -207,6 +211,9 @@ static int write_fcsr(CPURISCVState *env, int csrno, target_ulong val) env->vxsat = (val & FSR_VXSAT) >> FSR_VXSAT_SHIFT; } riscv_cpu_set_fflags(env, (val & FSR_AEXC) >> FSR_AEXC_SHIFT); + if (!riscv_cpu_set_rounding_mode(env, env->frm)) { + return -1; + } return 0; } diff --git a/target/riscv/fpu_helper.c b/target/riscv/fpu_helper.c index 0b79562a69..262610e837 100644 --- a/target/riscv/fpu_helper.c +++ b/target/riscv/fpu_helper.c @@ -50,13 +50,10 @@ void riscv_cpu_set_fflags(CPURISCVState *env, target_ulong hard) set_float_exception_flags(soft, &env->fp_status); } -void helper_set_rounding_mode(CPURISCVState *env, uint32_t rm) +bool riscv_cpu_set_rounding_mode(CPURISCVState *env, uint32_t rm) { int softrm; - if (rm == 7) { - rm = env->frm; - } switch (rm) { case 0: softrm = float_round_nearest_even; @@ -74,10 +71,22 @@ void helper_set_rounding_mode(CPURISCVState *env, uint32_t rm) softrm = float_round_ties_away; break; default: - riscv_raise_exception(env, RISCV_EXCP_ILLEGAL_INST, GETPC()); + return false; } set_float_rounding_mode(softrm, &env->fp_status); + return true; +} + +void helper_set_rounding_mode(CPURISCVState *env, uint32_t rm) +{ + if (rm == 7) { + rm = env->frm; + } + + if (!riscv_cpu_set_rounding_mode(env, rm)) { + riscv_raise_exception(env, RISCV_EXCP_ILLEGAL_INST, GETPC()); + } } uint64_t helper_fmadd_s(CPURISCVState *env, uint64_t frs1, uint64_t frs2, diff --git a/target/riscv/internals.h b/target/riscv/internals.h index f699d80c41..52f6af2513 100644 --- a/target/riscv/internals.h +++ b/target/riscv/internals.h @@ -27,4 +27,7 @@ FIELD(VDATA, VM, 8, 1) FIELD(VDATA, LMUL, 9, 2) FIELD(VDATA, NF, 11, 4) FIELD(VDATA, WD, 11, 1) + +/* set float rounding mode */ +bool riscv_cpu_set_rounding_mode(CPURISCVState *env, uint32_t rm); #endif -- 2.23.0