diff --git a/target-mips/cpu.h b/target-mips/cpu.h index f8299ad608..569f9325bf 100644 --- a/target-mips/cpu.h +++ b/target-mips/cpu.h @@ -414,24 +414,25 @@ struct CPUMIPSState { int user_mode_only; /* user mode only simulation */ uint32_t hflags; /* CPU State */ /* TMASK defines different execution modes */ -#define MIPS_HFLAG_TMASK 0x007F +#define MIPS_HFLAG_TMASK 0x00FF #define MIPS_HFLAG_MODE 0x0007 /* execution modes */ #define MIPS_HFLAG_UM 0x0001 /* user mode */ #define MIPS_HFLAG_DM 0x0002 /* Debug mode */ #define MIPS_HFLAG_SM 0x0004 /* Supervisor mode */ #define MIPS_HFLAG_64 0x0008 /* 64-bit instructions enabled */ -#define MIPS_HFLAG_FPU 0x0010 /* FPU enabled */ -#define MIPS_HFLAG_F64 0x0020 /* 64-bit FPU enabled */ -#define MIPS_HFLAG_RE 0x0040 /* Reversed endianness */ +#define MIPS_HFLAG_CP0 0x0010 /* CP0 enabled */ +#define MIPS_HFLAG_FPU 0x0020 /* FPU enabled */ +#define MIPS_HFLAG_F64 0x0040 /* 64-bit FPU enabled */ +#define MIPS_HFLAG_RE 0x0080 /* Reversed endianness */ /* If translation is interrupted between the branch instruction and * the delay slot, record what type of branch it is so that we can * resume translation properly. It might be possible to reduce * this from three bits to two. */ -#define MIPS_HFLAG_BMASK 0x0380 -#define MIPS_HFLAG_B 0x0080 /* Unconditional branch */ -#define MIPS_HFLAG_BC 0x0100 /* Conditional branch */ -#define MIPS_HFLAG_BL 0x0180 /* Likely branch */ -#define MIPS_HFLAG_BR 0x0200 /* branch to register (can't link TB) */ +#define MIPS_HFLAG_BMASK 0x0700 +#define MIPS_HFLAG_B 0x0100 /* Unconditional branch */ +#define MIPS_HFLAG_BC 0x0200 /* Conditional branch */ +#define MIPS_HFLAG_BL 0x0300 /* Likely branch */ +#define MIPS_HFLAG_BR 0x0400 /* branch to register (can't link TB) */ target_ulong btarget; /* Jump / branch target */ int bcond; /* Branch condition (if needed) */ diff --git a/target-mips/helper.c b/target-mips/helper.c index d0e5b1d481..5c19a7ca4a 100644 --- a/target-mips/helper.c +++ b/target-mips/helper.c @@ -371,6 +371,7 @@ void do_interrupt (CPUState *env) env->hflags |= MIPS_HFLAG_DM; env->hflags |= MIPS_HFLAG_64; env->hflags &= ~MIPS_HFLAG_UM; + env->hflags |= MIPS_HFLAG_CP0; /* EJTAG probe trap enable is not implemented... */ if (!(env->CP0_Status & (1 << CP0St_EXL))) env->CP0_Cause &= ~(1 << CP0Ca_BD); @@ -397,6 +398,7 @@ void do_interrupt (CPUState *env) env->CP0_Status |= (1 << CP0St_ERL) | (1 << CP0St_BEV); env->hflags |= MIPS_HFLAG_64; env->hflags &= ~MIPS_HFLAG_UM; + env->hflags |= MIPS_HFLAG_CP0; if (!(env->CP0_Status & (1 << CP0St_EXL))) env->CP0_Cause &= ~(1 << CP0Ca_BD); env->PC[env->current_tc] = (int32_t)0xBFC00000; @@ -499,6 +501,7 @@ void do_interrupt (CPUState *env) env->CP0_Status |= (1 << CP0St_EXL); env->hflags |= MIPS_HFLAG_64; env->hflags &= ~MIPS_HFLAG_UM; + env->hflags |= MIPS_HFLAG_CP0; } env->hflags &= ~MIPS_HFLAG_BMASK; if (env->CP0_Status & (1 << CP0St_BEV)) { diff --git a/target-mips/op.c b/target-mips/op.c index dd90163376..b3536442e3 100644 --- a/target-mips/op.c +++ b/target-mips/op.c @@ -1852,6 +1852,10 @@ void op_mtc0_status (void) !(val & (1 << CP0St_UX))) env->hflags &= ~MIPS_HFLAG_64; #endif + if ((val & (1 << CP0St_CU0)) || !(env->hflags & MIPS_HFLAG_UM)) + env->hflags |= MIPS_HFLAG_CP0; + else + env->hflags &= ~MIPS_HFLAG_CP0; if (val & (1 << CP0St_CU1)) env->hflags |= MIPS_HFLAG_FPU; else @@ -2316,15 +2320,6 @@ void op_yield(void) # define DEBUG_FPU_STATE() do { } while(0) #endif -void op_cp0_enabled(void) -{ - if (!(env->CP0_Status & (1 << CP0St_CU0)) && - (env->hflags & MIPS_HFLAG_UM)) { - CALL_FROM_TB2(do_raise_exception_err, EXCP_CpU, 0); - } - RETURN(); -} - void op_cfc1 (void) { CALL_FROM_TB1(do_cfc1, PARAM1); @@ -3018,6 +3013,10 @@ void op_eret (void) !(env->CP0_Status & (1 << CP0St_UX))) env->hflags &= ~MIPS_HFLAG_64; #endif + if ((env->CP0_Status & (1 << CP0St_CU0)) || !(env->hflags & MIPS_HFLAG_UM)) + env->hflags |= MIPS_HFLAG_CP0; + else + env->hflags &= ~MIPS_HFLAG_CP0; if (loglevel & CPU_LOG_EXEC) CALL_FROM_TB0(debug_post_eret); env->CP0_LLAddr = 1; @@ -3041,6 +3040,10 @@ void op_deret (void) !(env->CP0_Status & (1 << CP0St_UX))) env->hflags &= ~MIPS_HFLAG_64; #endif + if ((env->CP0_Status & (1 << CP0St_CU0)) || !(env->hflags & MIPS_HFLAG_UM)) + env->hflags |= MIPS_HFLAG_CP0; + else + env->hflags &= ~MIPS_HFLAG_CP0; if (loglevel & CPU_LOG_EXEC) CALL_FROM_TB0(debug_post_eret); env->CP0_LLAddr = 1; @@ -3049,9 +3052,8 @@ void op_deret (void) void op_rdhwr_cpunum(void) { - if (!(env->hflags & MIPS_HFLAG_UM) || - (env->CP0_HWREna & (1 << 0)) || - (env->CP0_Status & (1 << CP0St_CU0))) + if ((env->hflags & MIPS_HFLAG_CP0) || + (env->CP0_HWREna & (1 << 0))) T0 = env->CP0_EBase & 0x3ff; else CALL_FROM_TB1(do_raise_exception, EXCP_RI); @@ -3060,9 +3062,8 @@ void op_rdhwr_cpunum(void) void op_rdhwr_synci_step(void) { - if (!(env->hflags & MIPS_HFLAG_UM) || - (env->CP0_HWREna & (1 << 1)) || - (env->CP0_Status & (1 << CP0St_CU0))) + if ((env->hflags & MIPS_HFLAG_CP0) || + (env->CP0_HWREna & (1 << 1))) T0 = env->SYNCI_Step; else CALL_FROM_TB1(do_raise_exception, EXCP_RI); @@ -3071,9 +3072,8 @@ void op_rdhwr_synci_step(void) void op_rdhwr_cc(void) { - if (!(env->hflags & MIPS_HFLAG_UM) || - (env->CP0_HWREna & (1 << 2)) || - (env->CP0_Status & (1 << CP0St_CU0))) + if ((env->hflags & MIPS_HFLAG_CP0) || + (env->CP0_HWREna & (1 << 2))) T0 = env->CP0_Count; else CALL_FROM_TB1(do_raise_exception, EXCP_RI); @@ -3082,9 +3082,8 @@ void op_rdhwr_cc(void) void op_rdhwr_ccres(void) { - if (!(env->hflags & MIPS_HFLAG_UM) || - (env->CP0_HWREna & (1 << 3)) || - (env->CP0_Status & (1 << CP0St_CU0))) + if ((env->hflags & MIPS_HFLAG_CP0) || + (env->CP0_HWREna & (1 << 3))) T0 = env->CCRes; else CALL_FROM_TB1(do_raise_exception, EXCP_RI); diff --git a/target-mips/translate.c b/target-mips/translate.c index 004b2f701e..c70480cc7a 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -731,6 +731,12 @@ static inline void generate_exception (DisasContext *ctx, int excp) generate_exception_err (ctx, excp, 0); } +static inline void check_cp0_enabled(DisasContext *ctx) +{ + if (!(ctx->hflags & MIPS_HFLAG_CP0)) + generate_exception_err(ctx, EXCP_CpU, 1); +} + static inline void check_cp1_enabled(DisasContext *ctx) { if (!(ctx->hflags & MIPS_HFLAG_FPU)) @@ -4600,6 +4606,7 @@ static void gen_cp0 (CPUState *env, DisasContext *ctx, uint32_t opc, int rt, int break; case OPC_MTC0: GEN_LOAD_REG_TN(T0, rt); + save_cpu_state(ctx, 1); gen_mtc0(env, ctx, rd, ctx->opcode & 0x7); opn = "mtc0"; break; @@ -4617,6 +4624,7 @@ static void gen_cp0 (CPUState *env, DisasContext *ctx, uint32_t opc, int rt, int case OPC_DMTC0: check_insn(env, ctx, ISA_MIPS3); GEN_LOAD_REG_TN(T0, rt); + save_cpu_state(ctx, 1); gen_dmtc0(env, ctx, rd, ctx->opcode & 0x7); opn = "dmtc0"; break; @@ -4666,6 +4674,7 @@ static void gen_cp0 (CPUState *env, DisasContext *ctx, uint32_t opc, int rt, int case OPC_ERET: opn = "eret"; check_insn(env, ctx, ISA_MIPS2); + save_cpu_state(ctx, 1); gen_op_eret(); ctx->bstate = BS_EXCP; break; @@ -4676,6 +4685,7 @@ static void gen_cp0 (CPUState *env, DisasContext *ctx, uint32_t opc, int rt, int MIPS_INVAL(opn); generate_exception(ctx, EXCP_RI); } else { + save_cpu_state(ctx, 1); gen_op_deret(); ctx->bstate = BS_EXCP; } @@ -6183,8 +6193,7 @@ static void decode_opc (CPUState *env, DisasContext *ctx) } break; case OPC_CP0: - save_cpu_state(ctx, 1); - gen_op_cp0_enabled(); + check_cp0_enabled(ctx); op1 = MASK_CP0(ctx->opcode); switch (op1) { case OPC_MFC0: @@ -6221,12 +6230,14 @@ static void decode_opc (CPUState *env, DisasContext *ctx) break; case OPC_DI: check_insn(env, ctx, ISA_MIPS32R2); + save_cpu_state(ctx, 1); gen_op_di(); /* Stop translation as we may have switched the execution mode */ ctx->bstate = BS_STOP; break; case OPC_EI: check_insn(env, ctx, ISA_MIPS32R2); + save_cpu_state(ctx, 1); gen_op_ei(); /* Stop translation as we may have switched the execution mode */ ctx->bstate = BS_STOP; @@ -6747,7 +6758,6 @@ void cpu_reset (CPUMIPSState *env) } else { env->CP0_ErrorEPC = env->PC[env->current_tc]; } - env->hflags = 0; env->PC[env->current_tc] = (int32_t)0xBFC00000; env->CP0_Wired = 0; /* SMP not implemented */ @@ -6771,8 +6781,10 @@ void cpu_reset (CPUMIPSState *env) #endif env->exception_index = EXCP_NONE; #if defined(CONFIG_USER_ONLY) - env->hflags |= MIPS_HFLAG_UM; + env->hflags = MIPS_HFLAG_UM; env->user_mode_only = 1; +#else + env->hflags = MIPS_HFLAG_CP0; #endif }