From: Frank Chang <frank.ch...@sifive.com> When V=1, both vsstauts.FS and HS-level sstatus.FS are in effect. Modifying the floating-point state when V=1 causes both fields to be set to 3 (Dirty).
However, it's possible that HS-level sstatus.FS is Clean and VS-level vsstatus.FS is Dirty at the time mark_fs_dirty() is called when V=1. We can't early return for this case because we still need to set sstatus.FS to Dirty according to spec. Signed-off-by: Frank Chang <frank.ch...@sifive.com> Reviewed-by: Vincent Chen <vincent.c...@sifive.com> Tested-by: Vincent Chen <vincent.c...@sifive.com> --- target/riscv/translate.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/target/riscv/translate.c b/target/riscv/translate.c index e356fc6c46c..0096b098738 100644 --- a/target/riscv/translate.c +++ b/target/riscv/translate.c @@ -280,26 +280,27 @@ static void gen_jal(DisasContext *ctx, int rd, target_ulong imm) static void mark_fs_dirty(DisasContext *ctx) { TCGv tmp; - target_ulong sd; + target_ulong sd = is_32bit(ctx) ? MSTATUS32_SD : MSTATUS64_SD; + + if (ctx->virt_enabled) { + tmp = tcg_temp_new(); + tcg_gen_ld_tl(tmp, cpu_env, offsetof(CPURISCVState, mstatus_hs)); + tcg_gen_ori_tl(tmp, tmp, MSTATUS_FS | sd); + tcg_gen_st_tl(tmp, cpu_env, offsetof(CPURISCVState, mstatus_hs)); + tcg_temp_free(tmp); + } if (ctx->mstatus_fs == MSTATUS_FS) { return; } + /* Remember the state change for the rest of the TB. */ ctx->mstatus_fs = MSTATUS_FS; tmp = tcg_temp_new(); - sd = is_32bit(ctx) ? MSTATUS32_SD : MSTATUS64_SD; - tcg_gen_ld_tl(tmp, cpu_env, offsetof(CPURISCVState, mstatus)); tcg_gen_ori_tl(tmp, tmp, MSTATUS_FS | sd); tcg_gen_st_tl(tmp, cpu_env, offsetof(CPURISCVState, mstatus)); - - if (ctx->virt_enabled) { - tcg_gen_ld_tl(tmp, cpu_env, offsetof(CPURISCVState, mstatus_hs)); - tcg_gen_ori_tl(tmp, tmp, MSTATUS_FS | sd); - tcg_gen_st_tl(tmp, cpu_env, offsetof(CPURISCVState, mstatus_hs)); - } tcg_temp_free(tmp); } #else -- 2.25.1