diff --git a/cpu-exec.c b/cpu-exec.c index 926093afbb..60239d4b96 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -175,9 +175,13 @@ static inline TranslationBlock *tb_find_fast(void) pc = env->regs[15]; #elif defined(TARGET_SPARC) #ifdef TARGET_SPARC64 - flags = (env->pstate << 2) | ((env->lsu & (DMMU_E | IMMU_E)) >> 2); + // Combined FPU enable bits . PRIV . DMMU enabled . IMMU enabled + flags = (((env->pstate & PS_PEF) >> 1) | ((env->fprs & FPRS_FEF) << 2)) + | (env->pstate & PS_PRIV) | ((env->lsu & (DMMU_E | IMMU_E)) >> 2); #else - flags = env->psrs | ((env->mmuregs[0] & (MMU_E | MMU_NF)) << 1); + // FPU enable . MMU enabled . MMU no-fault . Supervisor + flags = (env->psref << 3) | ((env->mmuregs[0] & (MMU_E | MMU_NF)) << 1) + | env->psrs; #endif cs_base = env->npc; pc = env->pc; diff --git a/target-sparc/cpu.h b/target-sparc/cpu.h index 90f6fb23d8..d0bcd40674 100644 --- a/target-sparc/cpu.h +++ b/target-sparc/cpu.h @@ -78,6 +78,8 @@ #define PS_PRIV (1<<2) #define PS_IE (1<<1) #define PS_AG (1<<0) + +#define FPRS_FEF (1<<2) #endif /* Fcc */ diff --git a/target-sparc/op.c b/target-sparc/op.c index d5df859db1..f6d417f475 100644 --- a/target-sparc/op.c +++ b/target-sparc/op.c @@ -1017,15 +1017,6 @@ void OPPROTO op_trapcc_T0(void) FORCE_RET(); } -void OPPROTO op_trap_ifnofpu(void) -{ - if (!env->psref) { - env->exception_index = TT_NFPU_INSN; - cpu_loop_exit(); - } - FORCE_RET(); -} - void OPPROTO op_fpexception_im(void) { env->exception_index = TT_FP_EXCP; diff --git a/target-sparc/translate.c b/target-sparc/translate.c index 65ee97599d..26c81454a1 100644 --- a/target-sparc/translate.c +++ b/target-sparc/translate.c @@ -52,6 +52,7 @@ typedef struct DisasContext { target_ulong jump_pc[2]; /* used when JUMP_PC pc value is used */ int is_br; int mem_idx; + int fpu_enabled; struct TranslationBlock *tb; } DisasContext; @@ -935,6 +936,19 @@ static GenOpFunc * const gen_fcmpd[4] = { }; #endif +static int gen_trap_ifnofpu(DisasContext * dc) +{ +#if !defined(CONFIG_USER_ONLY) + if (!dc->fpu_enabled) { + save_state(dc); + gen_op_exception(TT_NFPU_INSN); + dc->is_br = 1; + return 1; + } +#endif + return 0; +} + /* before an instruction, dc->pc must be static */ static void disas_sparc_insn(DisasContext * dc) { @@ -981,10 +995,8 @@ static void disas_sparc_insn(DisasContext * dc) case 0x5: /* V9 FBPcc */ { int cc = GET_FIELD_SP(insn, 20, 21); -#if !defined(CONFIG_USER_ONLY) - save_state(dc); - gen_op_trap_ifnofpu(); -#endif + if (gen_trap_ifnofpu(dc)) + goto jmp_insn; target = GET_FIELD_SP(insn, 0, 18); target = sign_extend(target, 19); target <<= 2; @@ -1002,10 +1014,8 @@ static void disas_sparc_insn(DisasContext * dc) } case 0x6: /* FBN+x */ { -#if !defined(CONFIG_USER_ONLY) - save_state(dc); - gen_op_trap_ifnofpu(); -#endif + if (gen_trap_ifnofpu(dc)) + goto jmp_insn; target = GET_FIELD(insn, 10, 31); target = sign_extend(target, 22); target <<= 2; @@ -1079,16 +1089,16 @@ static void disas_sparc_insn(DisasContext * dc) } #endif } - save_state(dc); cond = GET_FIELD(insn, 3, 6); if (cond == 0x8) { + save_state(dc); gen_op_trap_T0(); - dc->is_br = 1; - goto jmp_insn; } else if (cond != 0) { #ifdef TARGET_SPARC64 /* V9 icc/xcc */ int cc = GET_FIELD_SP(insn, 11, 12); + flush_T2(dc); + save_state(dc); if (cc == 0) gen_cond[0][cond](); else if (cc == 2) @@ -1096,10 +1106,17 @@ static void disas_sparc_insn(DisasContext * dc) else goto illegal_insn; #else + flush_T2(dc); + save_state(dc); gen_cond[0][cond](); #endif gen_op_trapcc_T0(); } + gen_op_next_insn(); + gen_op_movl_T0_0(); + gen_op_exit_tb(); + dc->is_br = 1; + goto jmp_insn; } else if (xop == 0x28) { rs1 = GET_FIELD(insn, 13, 17); switch(rs1) { @@ -1241,10 +1258,8 @@ static void disas_sparc_insn(DisasContext * dc) break; #endif } else if (xop == 0x34) { /* FPU Operations */ -#if !defined(CONFIG_USER_ONLY) - save_state(dc); - gen_op_trap_ifnofpu(); -#endif + if (gen_trap_ifnofpu(dc)) + goto jmp_insn; rs1 = GET_FIELD(insn, 13, 17); rs2 = GET_FIELD(insn, 27, 31); xop = GET_FIELD(insn, 18, 26); @@ -1430,10 +1445,8 @@ static void disas_sparc_insn(DisasContext * dc) #ifdef TARGET_SPARC64 int cond; #endif -#if !defined(CONFIG_USER_ONLY) - save_state(dc); - gen_op_trap_ifnofpu(); -#endif + if (gen_trap_ifnofpu(dc)) + goto jmp_insn; rs1 = GET_FIELD(insn, 13, 17); rs2 = GET_FIELD(insn, 27, 31); xop = GET_FIELD(insn, 18, 26); @@ -2366,10 +2379,8 @@ static void disas_sparc_insn(DisasContext * dc) skip_move: ; #endif } else if (xop >= 0x20 && xop < 0x24) { -#if !defined(CONFIG_USER_ONLY) || defined(TARGET_SPARC64) - save_state(dc); - gen_op_trap_ifnofpu(); -#endif + if (gen_trap_ifnofpu(dc)) + goto jmp_insn; switch (xop) { case 0x20: /* load fpreg */ gen_op_ldst(ldf); @@ -2450,9 +2461,8 @@ static void disas_sparc_insn(DisasContext * dc) goto illegal_insn; } } else if (xop > 0x23 && xop < 0x28) { -#if !defined(CONFIG_USER_ONLY) - gen_op_trap_ifnofpu(); -#endif + if (gen_trap_ifnofpu(dc)) + goto jmp_insn; switch (xop) { case 0x24: gen_op_load_fpr_FT0(rd); @@ -2548,8 +2558,14 @@ static inline int gen_intermediate_code_internal(TranslationBlock * tb, dc->npc = (target_ulong) tb->cs_base; #if defined(CONFIG_USER_ONLY) dc->mem_idx = 0; + dc->fpu_enabled = 1; #else dc->mem_idx = ((env->psrs) != 0); +#ifdef TARGET_SPARC64 + dc->fpu_enabled = (((env->pstate & PS_PEF) != 0) && ((env->fprs & FPRS_FEF) != 0)); +#else + dc->fpu_enabled = ((env->psref) != 0); +#endif #endif gen_opc_ptr = gen_opc_buf; gen_opc_end = gen_opc_buf + OPC_MAX_SIZE;