mirror of https://github.com/xqemu/xqemu.git
Optimise instructions accessing CP0, by Aurelien Jarno.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3235 c046a42c-6fe2-441c-8c8c-71466251a162
This commit is contained in:
parent
b570094d9b
commit
387a8fe505
|
@ -414,24 +414,25 @@ struct CPUMIPSState {
|
||||||
int user_mode_only; /* user mode only simulation */
|
int user_mode_only; /* user mode only simulation */
|
||||||
uint32_t hflags; /* CPU State */
|
uint32_t hflags; /* CPU State */
|
||||||
/* TMASK defines different execution modes */
|
/* 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_MODE 0x0007 /* execution modes */
|
||||||
#define MIPS_HFLAG_UM 0x0001 /* user mode */
|
#define MIPS_HFLAG_UM 0x0001 /* user mode */
|
||||||
#define MIPS_HFLAG_DM 0x0002 /* Debug mode */
|
#define MIPS_HFLAG_DM 0x0002 /* Debug mode */
|
||||||
#define MIPS_HFLAG_SM 0x0004 /* Supervisor mode */
|
#define MIPS_HFLAG_SM 0x0004 /* Supervisor mode */
|
||||||
#define MIPS_HFLAG_64 0x0008 /* 64-bit instructions enabled */
|
#define MIPS_HFLAG_64 0x0008 /* 64-bit instructions enabled */
|
||||||
#define MIPS_HFLAG_FPU 0x0010 /* FPU enabled */
|
#define MIPS_HFLAG_CP0 0x0010 /* CP0 enabled */
|
||||||
#define MIPS_HFLAG_F64 0x0020 /* 64-bit FPU enabled */
|
#define MIPS_HFLAG_FPU 0x0020 /* FPU enabled */
|
||||||
#define MIPS_HFLAG_RE 0x0040 /* Reversed endianness */
|
#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
|
/* If translation is interrupted between the branch instruction and
|
||||||
* the delay slot, record what type of branch it is so that we can
|
* the delay slot, record what type of branch it is so that we can
|
||||||
* resume translation properly. It might be possible to reduce
|
* resume translation properly. It might be possible to reduce
|
||||||
* this from three bits to two. */
|
* this from three bits to two. */
|
||||||
#define MIPS_HFLAG_BMASK 0x0380
|
#define MIPS_HFLAG_BMASK 0x0700
|
||||||
#define MIPS_HFLAG_B 0x0080 /* Unconditional branch */
|
#define MIPS_HFLAG_B 0x0100 /* Unconditional branch */
|
||||||
#define MIPS_HFLAG_BC 0x0100 /* Conditional branch */
|
#define MIPS_HFLAG_BC 0x0200 /* Conditional branch */
|
||||||
#define MIPS_HFLAG_BL 0x0180 /* Likely branch */
|
#define MIPS_HFLAG_BL 0x0300 /* Likely branch */
|
||||||
#define MIPS_HFLAG_BR 0x0200 /* branch to register (can't link TB) */
|
#define MIPS_HFLAG_BR 0x0400 /* branch to register (can't link TB) */
|
||||||
target_ulong btarget; /* Jump / branch target */
|
target_ulong btarget; /* Jump / branch target */
|
||||||
int bcond; /* Branch condition (if needed) */
|
int bcond; /* Branch condition (if needed) */
|
||||||
|
|
||||||
|
|
|
@ -371,6 +371,7 @@ void do_interrupt (CPUState *env)
|
||||||
env->hflags |= MIPS_HFLAG_DM;
|
env->hflags |= MIPS_HFLAG_DM;
|
||||||
env->hflags |= MIPS_HFLAG_64;
|
env->hflags |= MIPS_HFLAG_64;
|
||||||
env->hflags &= ~MIPS_HFLAG_UM;
|
env->hflags &= ~MIPS_HFLAG_UM;
|
||||||
|
env->hflags |= MIPS_HFLAG_CP0;
|
||||||
/* EJTAG probe trap enable is not implemented... */
|
/* EJTAG probe trap enable is not implemented... */
|
||||||
if (!(env->CP0_Status & (1 << CP0St_EXL)))
|
if (!(env->CP0_Status & (1 << CP0St_EXL)))
|
||||||
env->CP0_Cause &= ~(1 << CP0Ca_BD);
|
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->CP0_Status |= (1 << CP0St_ERL) | (1 << CP0St_BEV);
|
||||||
env->hflags |= MIPS_HFLAG_64;
|
env->hflags |= MIPS_HFLAG_64;
|
||||||
env->hflags &= ~MIPS_HFLAG_UM;
|
env->hflags &= ~MIPS_HFLAG_UM;
|
||||||
|
env->hflags |= MIPS_HFLAG_CP0;
|
||||||
if (!(env->CP0_Status & (1 << CP0St_EXL)))
|
if (!(env->CP0_Status & (1 << CP0St_EXL)))
|
||||||
env->CP0_Cause &= ~(1 << CP0Ca_BD);
|
env->CP0_Cause &= ~(1 << CP0Ca_BD);
|
||||||
env->PC[env->current_tc] = (int32_t)0xBFC00000;
|
env->PC[env->current_tc] = (int32_t)0xBFC00000;
|
||||||
|
@ -499,6 +501,7 @@ void do_interrupt (CPUState *env)
|
||||||
env->CP0_Status |= (1 << CP0St_EXL);
|
env->CP0_Status |= (1 << CP0St_EXL);
|
||||||
env->hflags |= MIPS_HFLAG_64;
|
env->hflags |= MIPS_HFLAG_64;
|
||||||
env->hflags &= ~MIPS_HFLAG_UM;
|
env->hflags &= ~MIPS_HFLAG_UM;
|
||||||
|
env->hflags |= MIPS_HFLAG_CP0;
|
||||||
}
|
}
|
||||||
env->hflags &= ~MIPS_HFLAG_BMASK;
|
env->hflags &= ~MIPS_HFLAG_BMASK;
|
||||||
if (env->CP0_Status & (1 << CP0St_BEV)) {
|
if (env->CP0_Status & (1 << CP0St_BEV)) {
|
||||||
|
|
|
@ -1852,6 +1852,10 @@ void op_mtc0_status (void)
|
||||||
!(val & (1 << CP0St_UX)))
|
!(val & (1 << CP0St_UX)))
|
||||||
env->hflags &= ~MIPS_HFLAG_64;
|
env->hflags &= ~MIPS_HFLAG_64;
|
||||||
#endif
|
#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))
|
if (val & (1 << CP0St_CU1))
|
||||||
env->hflags |= MIPS_HFLAG_FPU;
|
env->hflags |= MIPS_HFLAG_FPU;
|
||||||
else
|
else
|
||||||
|
@ -2316,15 +2320,6 @@ void op_yield(void)
|
||||||
# define DEBUG_FPU_STATE() do { } while(0)
|
# define DEBUG_FPU_STATE() do { } while(0)
|
||||||
#endif
|
#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)
|
void op_cfc1 (void)
|
||||||
{
|
{
|
||||||
CALL_FROM_TB1(do_cfc1, PARAM1);
|
CALL_FROM_TB1(do_cfc1, PARAM1);
|
||||||
|
@ -3018,6 +3013,10 @@ void op_eret (void)
|
||||||
!(env->CP0_Status & (1 << CP0St_UX)))
|
!(env->CP0_Status & (1 << CP0St_UX)))
|
||||||
env->hflags &= ~MIPS_HFLAG_64;
|
env->hflags &= ~MIPS_HFLAG_64;
|
||||||
#endif
|
#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)
|
if (loglevel & CPU_LOG_EXEC)
|
||||||
CALL_FROM_TB0(debug_post_eret);
|
CALL_FROM_TB0(debug_post_eret);
|
||||||
env->CP0_LLAddr = 1;
|
env->CP0_LLAddr = 1;
|
||||||
|
@ -3041,6 +3040,10 @@ void op_deret (void)
|
||||||
!(env->CP0_Status & (1 << CP0St_UX)))
|
!(env->CP0_Status & (1 << CP0St_UX)))
|
||||||
env->hflags &= ~MIPS_HFLAG_64;
|
env->hflags &= ~MIPS_HFLAG_64;
|
||||||
#endif
|
#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)
|
if (loglevel & CPU_LOG_EXEC)
|
||||||
CALL_FROM_TB0(debug_post_eret);
|
CALL_FROM_TB0(debug_post_eret);
|
||||||
env->CP0_LLAddr = 1;
|
env->CP0_LLAddr = 1;
|
||||||
|
@ -3049,9 +3052,8 @@ void op_deret (void)
|
||||||
|
|
||||||
void op_rdhwr_cpunum(void)
|
void op_rdhwr_cpunum(void)
|
||||||
{
|
{
|
||||||
if (!(env->hflags & MIPS_HFLAG_UM) ||
|
if ((env->hflags & MIPS_HFLAG_CP0) ||
|
||||||
(env->CP0_HWREna & (1 << 0)) ||
|
(env->CP0_HWREna & (1 << 0)))
|
||||||
(env->CP0_Status & (1 << CP0St_CU0)))
|
|
||||||
T0 = env->CP0_EBase & 0x3ff;
|
T0 = env->CP0_EBase & 0x3ff;
|
||||||
else
|
else
|
||||||
CALL_FROM_TB1(do_raise_exception, EXCP_RI);
|
CALL_FROM_TB1(do_raise_exception, EXCP_RI);
|
||||||
|
@ -3060,9 +3062,8 @@ void op_rdhwr_cpunum(void)
|
||||||
|
|
||||||
void op_rdhwr_synci_step(void)
|
void op_rdhwr_synci_step(void)
|
||||||
{
|
{
|
||||||
if (!(env->hflags & MIPS_HFLAG_UM) ||
|
if ((env->hflags & MIPS_HFLAG_CP0) ||
|
||||||
(env->CP0_HWREna & (1 << 1)) ||
|
(env->CP0_HWREna & (1 << 1)))
|
||||||
(env->CP0_Status & (1 << CP0St_CU0)))
|
|
||||||
T0 = env->SYNCI_Step;
|
T0 = env->SYNCI_Step;
|
||||||
else
|
else
|
||||||
CALL_FROM_TB1(do_raise_exception, EXCP_RI);
|
CALL_FROM_TB1(do_raise_exception, EXCP_RI);
|
||||||
|
@ -3071,9 +3072,8 @@ void op_rdhwr_synci_step(void)
|
||||||
|
|
||||||
void op_rdhwr_cc(void)
|
void op_rdhwr_cc(void)
|
||||||
{
|
{
|
||||||
if (!(env->hflags & MIPS_HFLAG_UM) ||
|
if ((env->hflags & MIPS_HFLAG_CP0) ||
|
||||||
(env->CP0_HWREna & (1 << 2)) ||
|
(env->CP0_HWREna & (1 << 2)))
|
||||||
(env->CP0_Status & (1 << CP0St_CU0)))
|
|
||||||
T0 = env->CP0_Count;
|
T0 = env->CP0_Count;
|
||||||
else
|
else
|
||||||
CALL_FROM_TB1(do_raise_exception, EXCP_RI);
|
CALL_FROM_TB1(do_raise_exception, EXCP_RI);
|
||||||
|
@ -3082,9 +3082,8 @@ void op_rdhwr_cc(void)
|
||||||
|
|
||||||
void op_rdhwr_ccres(void)
|
void op_rdhwr_ccres(void)
|
||||||
{
|
{
|
||||||
if (!(env->hflags & MIPS_HFLAG_UM) ||
|
if ((env->hflags & MIPS_HFLAG_CP0) ||
|
||||||
(env->CP0_HWREna & (1 << 3)) ||
|
(env->CP0_HWREna & (1 << 3)))
|
||||||
(env->CP0_Status & (1 << CP0St_CU0)))
|
|
||||||
T0 = env->CCRes;
|
T0 = env->CCRes;
|
||||||
else
|
else
|
||||||
CALL_FROM_TB1(do_raise_exception, EXCP_RI);
|
CALL_FROM_TB1(do_raise_exception, EXCP_RI);
|
||||||
|
|
|
@ -731,6 +731,12 @@ static inline void generate_exception (DisasContext *ctx, int excp)
|
||||||
generate_exception_err (ctx, excp, 0);
|
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)
|
static inline void check_cp1_enabled(DisasContext *ctx)
|
||||||
{
|
{
|
||||||
if (!(ctx->hflags & MIPS_HFLAG_FPU))
|
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;
|
break;
|
||||||
case OPC_MTC0:
|
case OPC_MTC0:
|
||||||
GEN_LOAD_REG_TN(T0, rt);
|
GEN_LOAD_REG_TN(T0, rt);
|
||||||
|
save_cpu_state(ctx, 1);
|
||||||
gen_mtc0(env, ctx, rd, ctx->opcode & 0x7);
|
gen_mtc0(env, ctx, rd, ctx->opcode & 0x7);
|
||||||
opn = "mtc0";
|
opn = "mtc0";
|
||||||
break;
|
break;
|
||||||
|
@ -4617,6 +4624,7 @@ static void gen_cp0 (CPUState *env, DisasContext *ctx, uint32_t opc, int rt, int
|
||||||
case OPC_DMTC0:
|
case OPC_DMTC0:
|
||||||
check_insn(env, ctx, ISA_MIPS3);
|
check_insn(env, ctx, ISA_MIPS3);
|
||||||
GEN_LOAD_REG_TN(T0, rt);
|
GEN_LOAD_REG_TN(T0, rt);
|
||||||
|
save_cpu_state(ctx, 1);
|
||||||
gen_dmtc0(env, ctx, rd, ctx->opcode & 0x7);
|
gen_dmtc0(env, ctx, rd, ctx->opcode & 0x7);
|
||||||
opn = "dmtc0";
|
opn = "dmtc0";
|
||||||
break;
|
break;
|
||||||
|
@ -4666,6 +4674,7 @@ static void gen_cp0 (CPUState *env, DisasContext *ctx, uint32_t opc, int rt, int
|
||||||
case OPC_ERET:
|
case OPC_ERET:
|
||||||
opn = "eret";
|
opn = "eret";
|
||||||
check_insn(env, ctx, ISA_MIPS2);
|
check_insn(env, ctx, ISA_MIPS2);
|
||||||
|
save_cpu_state(ctx, 1);
|
||||||
gen_op_eret();
|
gen_op_eret();
|
||||||
ctx->bstate = BS_EXCP;
|
ctx->bstate = BS_EXCP;
|
||||||
break;
|
break;
|
||||||
|
@ -4676,6 +4685,7 @@ static void gen_cp0 (CPUState *env, DisasContext *ctx, uint32_t opc, int rt, int
|
||||||
MIPS_INVAL(opn);
|
MIPS_INVAL(opn);
|
||||||
generate_exception(ctx, EXCP_RI);
|
generate_exception(ctx, EXCP_RI);
|
||||||
} else {
|
} else {
|
||||||
|
save_cpu_state(ctx, 1);
|
||||||
gen_op_deret();
|
gen_op_deret();
|
||||||
ctx->bstate = BS_EXCP;
|
ctx->bstate = BS_EXCP;
|
||||||
}
|
}
|
||||||
|
@ -6183,8 +6193,7 @@ static void decode_opc (CPUState *env, DisasContext *ctx)
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case OPC_CP0:
|
case OPC_CP0:
|
||||||
save_cpu_state(ctx, 1);
|
check_cp0_enabled(ctx);
|
||||||
gen_op_cp0_enabled();
|
|
||||||
op1 = MASK_CP0(ctx->opcode);
|
op1 = MASK_CP0(ctx->opcode);
|
||||||
switch (op1) {
|
switch (op1) {
|
||||||
case OPC_MFC0:
|
case OPC_MFC0:
|
||||||
|
@ -6221,12 +6230,14 @@ static void decode_opc (CPUState *env, DisasContext *ctx)
|
||||||
break;
|
break;
|
||||||
case OPC_DI:
|
case OPC_DI:
|
||||||
check_insn(env, ctx, ISA_MIPS32R2);
|
check_insn(env, ctx, ISA_MIPS32R2);
|
||||||
|
save_cpu_state(ctx, 1);
|
||||||
gen_op_di();
|
gen_op_di();
|
||||||
/* Stop translation as we may have switched the execution mode */
|
/* Stop translation as we may have switched the execution mode */
|
||||||
ctx->bstate = BS_STOP;
|
ctx->bstate = BS_STOP;
|
||||||
break;
|
break;
|
||||||
case OPC_EI:
|
case OPC_EI:
|
||||||
check_insn(env, ctx, ISA_MIPS32R2);
|
check_insn(env, ctx, ISA_MIPS32R2);
|
||||||
|
save_cpu_state(ctx, 1);
|
||||||
gen_op_ei();
|
gen_op_ei();
|
||||||
/* Stop translation as we may have switched the execution mode */
|
/* Stop translation as we may have switched the execution mode */
|
||||||
ctx->bstate = BS_STOP;
|
ctx->bstate = BS_STOP;
|
||||||
|
@ -6747,7 +6758,6 @@ void cpu_reset (CPUMIPSState *env)
|
||||||
} else {
|
} else {
|
||||||
env->CP0_ErrorEPC = env->PC[env->current_tc];
|
env->CP0_ErrorEPC = env->PC[env->current_tc];
|
||||||
}
|
}
|
||||||
env->hflags = 0;
|
|
||||||
env->PC[env->current_tc] = (int32_t)0xBFC00000;
|
env->PC[env->current_tc] = (int32_t)0xBFC00000;
|
||||||
env->CP0_Wired = 0;
|
env->CP0_Wired = 0;
|
||||||
/* SMP not implemented */
|
/* SMP not implemented */
|
||||||
|
@ -6771,8 +6781,10 @@ void cpu_reset (CPUMIPSState *env)
|
||||||
#endif
|
#endif
|
||||||
env->exception_index = EXCP_NONE;
|
env->exception_index = EXCP_NONE;
|
||||||
#if defined(CONFIG_USER_ONLY)
|
#if defined(CONFIG_USER_ONLY)
|
||||||
env->hflags |= MIPS_HFLAG_UM;
|
env->hflags = MIPS_HFLAG_UM;
|
||||||
env->user_mode_only = 1;
|
env->user_mode_only = 1;
|
||||||
|
#else
|
||||||
|
env->hflags = MIPS_HFLAG_CP0;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue