Hi all, The patch below optimise instructions accessing CP0 by doing access rights check at translation time instead of execution time, as it is already done for other CPx.
This is done by adding a new bit to hflags. Unfortunately that means reorganising them because there was no space anymore for a new bit. Bye, Aurelien Index: target-mips/cpu.h =================================================================== RCS file: /sources/qemu/qemu/target-mips/cpu.h,v retrieving revision 1.44 diff -u -d -p -r1.44 cpu.h --- target-mips/cpu.h 24 Sep 2007 12:48:00 -0000 1.44 +++ target-mips/cpu.h 24 Sep 2007 14:02:55 -0000 @@ -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) */ Index: target-mips/helper.c =================================================================== RCS file: /sources/qemu/qemu/target-mips/helper.c,v retrieving revision 1.49 diff -u -d -p -r1.49 helper.c --- target-mips/helper.c 24 Sep 2007 12:48:00 -0000 1.49 +++ target-mips/helper.c 24 Sep 2007 14:02:55 -0000 @@ -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)) { Index: target-mips/op.c =================================================================== RCS file: /sources/qemu/qemu/target-mips/op.c,v retrieving revision 1.72 diff -u -d -p -r1.72 op.c --- target-mips/op.c 24 Sep 2007 12:48:00 -0000 1.72 +++ target-mips/op.c 24 Sep 2007 14:02:56 -0000 @@ -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); Index: target-mips/translate.c =================================================================== RCS file: /sources/qemu/qemu/target-mips/translate.c,v retrieving revision 1.101 diff -u -d -p -r1.101 translate.c --- target-mips/translate.c 24 Sep 2007 12:48:00 -0000 1.101 +++ target-mips/translate.c 24 Sep 2007 14:02:58 -0000 @@ -731,6 +731,12 @@ static inline void generate_exception (D 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, Disa 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, Disa 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, Disa 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, Disa 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, D } 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, D 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 } -- .''`. Aurelien Jarno | GPG: 1024D/F1BCDB73 : :' : Debian developer | Electrical Engineer `. `' [EMAIL PROTECTED] | [EMAIL PROTECTED] `- people.debian.org/~aurel32 | www.aurel32.net