diff --git a/qemu/target-mips/cpu.h b/qemu/target-mips/cpu.h index 2146ca9a..78858521 100644 --- a/qemu/target-mips/cpu.h +++ b/qemu/target-mips/cpu.h @@ -101,6 +101,7 @@ struct CPUMIPSFPUContext { float_status fp_status; /* fpu implementation/revision register (fir) */ uint32_t fcr0; +#define FCR0_FREP 29 #define FCR0_UFRP 28 #define FCR0_F64 22 #define FCR0_L 21 @@ -463,6 +464,8 @@ struct CPUMIPSState { #define CP0C5_CV 29 #define CP0C5_EVA 28 #define CP0C5_MSAEn 27 +#define CP0C5_UFE 9 +#define CP0C5_FRE 8 #define CP0C5_SBRI 6 #define CP0C5_UFR 2 #define CP0C5_NFExists 0 @@ -515,7 +518,7 @@ struct CPUMIPSState { #define EXCP_INST_NOTAVAIL 0x2 /* No valid instruction word for BadInstr */ uint32_t hflags; /* CPU State */ /* TMASK defines different execution modes */ -#define MIPS_HFLAG_TMASK 0x15807FF +#define MIPS_HFLAG_TMASK 0x35807FF #define MIPS_HFLAG_MODE 0x00007 /* execution modes */ /* The KSU flags must be the lowest bits in hflags. The flag order must be the same as defined for CP0 Status. This allows to use @@ -561,7 +564,8 @@ struct CPUMIPSState { #define MIPS_HFLAG_HWRENA_ULR 0x200000 /* ULR bit from HWREna is set. */ #define MIPS_HFLAG_SBRI 0x400000 /* R6 SDBBP causes RI excpt. in user mode */ #define MIPS_HFLAG_FBNSLOT 0x800000 /* Forbidden slot */ -#define MIPS_HFLAG_MSA 0x1000000 +#define MIPS_HFLAG_MSA 0x1000000 /* FRE enabled */ +#define MIPS_HFLAG_FRE 0x2000000 /* FRE enabled */ target_ulong btarget; /* Jump / branch target */ target_ulong bcond; /* Branch condition (if needed) */ @@ -847,7 +851,7 @@ static inline void compute_hflags(CPUMIPSState *env) env->hflags &= ~(MIPS_HFLAG_COP1X | MIPS_HFLAG_64 | MIPS_HFLAG_CP0 | MIPS_HFLAG_F64 | MIPS_HFLAG_FPU | MIPS_HFLAG_KSU | MIPS_HFLAG_AWRAP | MIPS_HFLAG_DSP | MIPS_HFLAG_DSPR2 | - MIPS_HFLAG_SBRI | MIPS_HFLAG_MSA); + MIPS_HFLAG_SBRI | MIPS_HFLAG_MSA | MIPS_HFLAG_FRE); if (!(env->CP0_Status & (1 << CP0St_EXL)) && !(env->CP0_Status & (1 << CP0St_ERL)) && !(env->hflags & MIPS_HFLAG_DM)) { @@ -928,6 +932,11 @@ static inline void compute_hflags(CPUMIPSState *env) env->hflags |= MIPS_HFLAG_MSA; } } + if (env->active_fpu.fcr0 & (1 << FCR0_FREP)) { + if (env->CP0_Config5 & (1 << CP0C5_FRE)) { + env->hflags |= MIPS_HFLAG_FRE; + } + } } #ifndef CONFIG_USER_ONLY diff --git a/qemu/target-mips/op_helper.c b/qemu/target-mips/op_helper.c index 3e28c65a..ff23b765 100644 --- a/qemu/target-mips/op_helper.c +++ b/qemu/target-mips/op_helper.c @@ -2306,6 +2306,16 @@ target_ulong helper_cfc1(CPUMIPSState *env, uint32_t reg) } } break; + case 5: + /* FRE Support - read Config5.FRE bit */ + if (env->active_fpu.fcr0 & (1 << FCR0_FREP)) { + if (env->CP0_Config5 & (1 << CP0C5_UFE)) { + arg1 = (env->CP0_Config5 >> CP0C5_FRE) & 1; + } else { + helper_raise_exception(env, EXCP_RI); + } + } + break; case 25: arg1 = ((env->active_fpu.fcr31 >> 24) & 0xfe) | ((env->active_fpu.fcr31 >> 23) & 0x1); break; @@ -2350,6 +2360,30 @@ void helper_ctc1(CPUMIPSState *env, target_ulong arg1, uint32_t fs, uint32_t rt) helper_raise_exception(env, EXCP_RI); } break; + case 5: + /* FRE Support - clear Config5.FRE bit */ + if (!((env->active_fpu.fcr0 & (1 << FCR0_FREP)) && (rt == 0))) { + return; + } + if (env->CP0_Config5 & (1 << CP0C5_UFE)) { + env->CP0_Config5 &= ~(1 << CP0C5_FRE); + compute_hflags(env); + } else { + helper_raise_exception(env, EXCP_RI); + } + break; + case 6: + /* FRE Support - set Config5.FRE bit */ + if (!((env->active_fpu.fcr0 & (1 << FCR0_FREP)) && (rt == 0))) { + return; + } + if (env->CP0_Config5 & (1 << CP0C5_UFE)) { + env->CP0_Config5 |= (1 << CP0C5_FRE); + compute_hflags(env); + } else { + helper_raise_exception(env, EXCP_RI); + } + break; case 25: if ((env->insn_flags & ISA_MIPS32R6) || (arg1 & 0xffffff00)) { return; diff --git a/qemu/target-mips/translate.c b/qemu/target-mips/translate.c index fb655932..cbcde654 100644 --- a/qemu/target-mips/translate.c +++ b/qemu/target-mips/translate.c @@ -1548,20 +1548,22 @@ static inline void gen_store_srsgpr (DisasContext *s, int from, int to) } /* Tests */ -static inline void gen_save_pc(target_ulong pc) +static inline void gen_save_pc(DisasContext *ctx, target_ulong pc) { - tcg_gen_movi_tl(cpu_PC, pc); + TCGContext *tcg_ctx = ctx->uc->tcg_ctx; + tcg_gen_movi_tl(tcg_ctx, *(TCGv *)tcg_ctx->cpu_PC, pc); } static inline void save_cpu_state(DisasContext *ctx, int do_save_pc) { + TCGContext *tcg_ctx = ctx->uc->tcg_ctx; LOG_DISAS("hflags %08x saved %08x\n", ctx->hflags, ctx->saved_hflags); if (do_save_pc && ctx->pc != ctx->saved_pc) { - gen_save_pc(ctx->pc); + gen_save_pc(ctx, ctx->pc); ctx->saved_pc = ctx->pc; } if (ctx->hflags != ctx->saved_hflags) { - tcg_gen_movi_i32(hflags, ctx->hflags); + tcg_gen_movi_i32(tcg_ctx, tcg_ctx->hflags, ctx->hflags); ctx->saved_hflags = ctx->hflags; switch (ctx->hflags & MIPS_HFLAG_BMASK_BASE) { case MIPS_HFLAG_BR: @@ -1569,7 +1571,7 @@ static inline void save_cpu_state(DisasContext *ctx, int do_save_pc) case MIPS_HFLAG_BC: case MIPS_HFLAG_BL: case MIPS_HFLAG_B: - tcg_gen_movi_tl(btarget, ctx->btarget); + tcg_gen_movi_tl(tcg_ctx, *(TCGv *)tcg_ctx->btarget, ctx->btarget); break; } } @@ -1591,31 +1593,41 @@ static inline void restore_cpu_state(CPUMIPSState *env, DisasContext *ctx) static inline void generate_exception_err(DisasContext *ctx, int excp, int err) { - TCGv_i32 texcp = tcg_const_i32(excp); - TCGv_i32 terr = tcg_const_i32(err); + TCGContext *tcg_ctx = ctx->uc->tcg_ctx; + TCGv_i32 texcp = tcg_const_i32(tcg_ctx, excp); + TCGv_i32 terr = tcg_const_i32(tcg_ctx, err); save_cpu_state(ctx, 1); - gen_helper_raise_exception_err(cpu_env, texcp, terr); - tcg_temp_free_i32(terr); - tcg_temp_free_i32(texcp); + gen_helper_raise_exception_err(tcg_ctx, tcg_ctx->cpu_env, texcp, terr); + tcg_temp_free_i32(tcg_ctx, terr); + tcg_temp_free_i32(tcg_ctx, texcp); } static inline void generate_exception(DisasContext *ctx, int excp) { + TCGContext *tcg_ctx = ctx->uc->tcg_ctx; save_cpu_state(ctx, 1); - gen_helper_0e0i(raise_exception, excp); + gen_helper_0e0i(tcg_ctx, raise_exception, excp); } /* Floating point register moves. */ -static void gen_load_fpr32(DisasContext *s, TCGv_i32 t, int reg) +static void gen_load_fpr32(DisasContext *ctx, TCGv_i32 t, int reg) { - TCGContext *tcg_ctx = s->uc->tcg_ctx; + TCGContext *tcg_ctx = ctx->uc->tcg_ctx; + + if (ctx->hflags & MIPS_HFLAG_FRE) { + generate_exception(ctx, EXCP_RI); + } tcg_gen_extrl_i64_i32(tcg_ctx, t, tcg_ctx->fpu_f64[reg]); } -static void gen_store_fpr32(DisasContext *s, TCGv_i32 t, int reg) +static void gen_store_fpr32(DisasContext *ctx, TCGv_i32 t, int reg) { - TCGContext *tcg_ctx = s->uc->tcg_ctx; - TCGv_i64 t64 = tcg_temp_new_i64(tcg_ctx); + TCGContext *tcg_ctx = ctx->uc->tcg_ctx; + TCGv_i64 t64; + if (ctx->hflags & MIPS_HFLAG_FRE) { + generate_exception(ctx, EXCP_RI); + } + t64 = tcg_temp_new_i64(tcg_ctx); tcg_gen_extu_i32_i64(tcg_ctx, t64, t); tcg_gen_deposit_i64(tcg_ctx, tcg_ctx->fpu_f64[reg], tcg_ctx->fpu_f64[reg], t64, 0, 32); tcg_temp_free_i64(tcg_ctx, t64); @@ -8523,7 +8535,8 @@ static void gen_movci (DisasContext *ctx, int rd, int rs, int cc, int tf) gen_set_label(tcg_ctx, l1); } -static inline void gen_movcf_s (DisasContext *ctx, int fs, int fd, int cc, int tf) +static inline void gen_movcf_s(DisasContext *ctx, int fs, int fd, int cc, + int tf) { TCGContext *tcg_ctx = ctx->uc->tcg_ctx; int cond; diff --git a/qemu/target-mips/translate_init.c b/qemu/target-mips/translate_init.c index 94d3fc36..a5d34903 100644 --- a/qemu/target-mips/translate_init.c +++ b/qemu/target-mips/translate_init.c @@ -739,7 +739,7 @@ static const mips_def_t mips_defs[] = (3 << CP0C4_IE) | (1 << CP0C4_M), 0, 0, - (1 << CP0C5_SBRI), + (1 << CP0C5_SBRI) | (1 << CP0C5_FRE) | (1 << CP0C5_UFE), 0, 0, 0, @@ -749,9 +749,9 @@ static const mips_def_t mips_defs[] = 0x30D8FFFF, 0, 0, - (1 << FCR0_F64) | (1 << FCR0_L) | (1 << FCR0_W) | - (1 << FCR0_D) | (1 << FCR0_S) | (0x00 << FCR0_PRID) | - (0x0 << FCR0_REV), + (1 << FCR0_FREP) | (1 << FCR0_F64) | (1 << FCR0_L) | + (1 << FCR0_W) | (1 << FCR0_D) | (1 << FCR0_S) | + (0x00 << FCR0_PRID) | (0x0 << FCR0_REV), 0, 42, /* The architectural limit is 59, but we have hardcoded 36 bit