diff options
-rw-r--r-- | target/riscv/op_helper.c | 17 |
1 files changed, 15 insertions, 2 deletions
diff --git a/target/riscv/op_helper.c b/target/riscv/op_helper.c index e34715df4e..7c6068bac9 100644 --- a/target/riscv/op_helper.c +++ b/target/riscv/op_helper.c @@ -144,8 +144,21 @@ void csr_write_helper(CPURISCVState *env, target_ulong val_to_write, } mstatus = (mstatus & ~mask) | (val_to_write & mask); - int dirty = (mstatus & MSTATUS_FS) == MSTATUS_FS; - dirty |= (mstatus & MSTATUS_XS) == MSTATUS_XS; + + /* Note: this is a workaround for an issue where mstatus.FS + does not report dirty after floating point operations + that modify floating point state. This workaround is + technically compliant with the RISC-V Privileged + specification as it is legal to return only off, or dirty. + at the expense of extra floating point save/restore. */ + + /* FP is always dirty or off */ + if (mstatus & MSTATUS_FS) { + mstatus |= MSTATUS_FS; + } + + int dirty = ((mstatus & MSTATUS_FS) == MSTATUS_FS) | + ((mstatus & MSTATUS_XS) == MSTATUS_XS); mstatus = set_field(mstatus, MSTATUS_SD, dirty); env->mstatus = mstatus; break; |