From 6e473128b61901441fa2889dfa2079881895a9f9 Mon Sep 17 00:00:00 2001 From: ths Date: Mon, 28 May 2007 20:36:48 +0000 Subject: Handle PX/UX status flags correctly, by Aurelien Jarno. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2892 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/cpu.h | 1 + target-mips/helper.c | 3 +++ target-mips/op.c | 18 ++++++++++++++++++ target-mips/translate.c | 33 ++++++++++++++++++++++++++------- 4 files changed, 48 insertions(+), 7 deletions(-) (limited to 'target-mips') diff --git a/target-mips/cpu.h b/target-mips/cpu.h index 9cddc174d2..17ac4ac875 100644 --- a/target-mips/cpu.h +++ b/target-mips/cpu.h @@ -260,6 +260,7 @@ struct CPUMIPSState { #define MIPS_HFLAG_UM 0x0001 /* user mode */ #define MIPS_HFLAG_DM 0x0008 /* Debug mode */ #define MIPS_HFLAG_SM 0x0010 /* Supervisor mode */ +#define MIPS_HFLAG_64 0x0020 /* 64-bit instructions enabled */ #define MIPS_HFLAG_RE 0x0040 /* 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 diff --git a/target-mips/helper.c b/target-mips/helper.c index 2dfaffc23f..9da6212a59 100644 --- a/target-mips/helper.c +++ b/target-mips/helper.c @@ -370,6 +370,7 @@ void do_interrupt (CPUState *env) } enter_debug_mode: env->hflags |= MIPS_HFLAG_DM; + env->hflags |= MIPS_HFLAG_64; env->hflags &= ~MIPS_HFLAG_UM; /* EJTAG probe trap enable is not implemented... */ if (!(env->CP0_Status & (1 << CP0St_EXL))) @@ -395,6 +396,7 @@ void do_interrupt (CPUState *env) env->CP0_ErrorEPC = env->PC; } env->CP0_Status |= (1 << CP0St_ERL) | (1 << CP0St_BEV); + env->hflags |= MIPS_HFLAG_64; env->hflags &= ~MIPS_HFLAG_UM; if (!(env->CP0_Status & (1 << CP0St_EXL))) env->CP0_Cause &= ~(1 << CP0Ca_BD); @@ -493,6 +495,7 @@ void do_interrupt (CPUState *env) env->CP0_Cause &= ~(1 << CP0Ca_BD); } env->CP0_Status |= (1 << CP0St_EXL); + env->hflags |= MIPS_HFLAG_64; env->hflags &= ~MIPS_HFLAG_UM; } env->hflags &= ~MIPS_HFLAG_BMASK; diff --git a/target-mips/op.c b/target-mips/op.c index f4598fb46c..bc4d51a8f8 100644 --- a/target-mips/op.c +++ b/target-mips/op.c @@ -1358,6 +1358,12 @@ void op_mtc0_status (void) !(env->hflags & MIPS_HFLAG_DM) && (val & (1 << CP0St_UM))) env->hflags |= MIPS_HFLAG_UM; +#ifdef TARGET_MIPS64 + if ((env->hflags & MIPS_HFLAG_UM) && + !(val & (1 << CP0St_PX)) && + !(val & (1 << CP0St_UX))) + env->hflags &= ~MIPS_HFLAG_64; +#endif env->CP0_Status = (env->CP0_Status & ~mask) | val; if (loglevel & CPU_LOG_EXEC) CALL_FROM_TB2(do_mtc0_status_debug, old, val); @@ -2338,6 +2344,12 @@ void op_eret (void) !(env->hflags & MIPS_HFLAG_DM) && (env->CP0_Status & (1 << CP0St_UM))) env->hflags |= MIPS_HFLAG_UM; +#ifdef TARGET_MIPS64 + if ((env->hflags & MIPS_HFLAG_UM) && + !(env->CP0_Status & (1 << CP0St_PX)) && + !(env->CP0_Status & (1 << CP0St_UX))) + env->hflags &= ~MIPS_HFLAG_64; +#endif if (loglevel & CPU_LOG_EXEC) CALL_FROM_TB0(debug_post_eret); env->CP0_LLAddr = 1; @@ -2355,6 +2367,12 @@ void op_deret (void) !(env->hflags & MIPS_HFLAG_DM) && (env->CP0_Status & (1 << CP0St_UM))) env->hflags |= MIPS_HFLAG_UM; +#ifdef TARGET_MIPS64 + if ((env->hflags & MIPS_HFLAG_UM) && + !(env->CP0_Status & (1 << CP0St_PX)) && + !(env->CP0_Status & (1 << CP0St_UX))) + env->hflags &= ~MIPS_HFLAG_64; +#endif if (loglevel & CPU_LOG_EXEC) CALL_FROM_TB0(debug_post_eret); env->CP0_LLAddr = 1; diff --git a/target-mips/translate.c b/target-mips/translate.c index ffa5c4bc9f..c0f2b81229 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -730,9 +730,9 @@ OP_ST_TABLE(dl); OP_ST_TABLE(dr); OP_LD_TABLE(ld); OP_ST_TABLE(cd); +OP_LD_TABLE(wu); #endif OP_LD_TABLE(w); -OP_LD_TABLE(wu); OP_LD_TABLE(wl); OP_LD_TABLE(wr); OP_ST_TABLE(w); @@ -773,6 +773,11 @@ static void gen_ldst (DisasContext *ctx, uint32_t opc, int rt, */ switch (opc) { #ifdef TARGET_MIPS64 + case OPC_LWU: + op_ldst(lwu); + GEN_STORE_TN_REG(rt, T0); + opn = "lwu"; + break; case OPC_LD: op_ldst(ld); GEN_STORE_TN_REG(rt, T0); @@ -823,11 +828,6 @@ static void gen_ldst (DisasContext *ctx, uint32_t opc, int rt, GEN_STORE_TN_REG(rt, T0); opn = "lw"; break; - case OPC_LWU: - op_ldst(lwu); - GEN_STORE_TN_REG(rt, T0); - opn = "lwu"; - break; case OPC_SW: GEN_LOAD_REG_TN(T1, rt); op_ldst(sw); @@ -5377,14 +5377,20 @@ static void decode_opc (CPUState *env, DisasContext *ctx) case OPC_DSRL ... OPC_DSRA: case OPC_DSLL32: case OPC_DSRL32 ... OPC_DSRA32: + if (!(ctx->hflags & MIPS_HFLAG_64)) + generate_exception(ctx, EXCP_RI); gen_arith_imm(ctx, op1, rd, rt, sa); break; case OPC_DSLLV: case OPC_DSRLV ... OPC_DSRAV: case OPC_DADD ... OPC_DSUBU: + if (!(ctx->hflags & MIPS_HFLAG_64)) + generate_exception(ctx, EXCP_RI); gen_arith(ctx, op1, rd, rs, rt); break; case OPC_DMULT ... OPC_DDIVU: + if (!(ctx->hflags & MIPS_HFLAG_64)) + generate_exception(ctx, EXCP_RI); gen_muldiv(ctx, op1, rs, rt); break; #endif @@ -5420,6 +5426,8 @@ static void decode_opc (CPUState *env, DisasContext *ctx) break; #ifdef TARGET_MIPS64 case OPC_DCLZ ... OPC_DCLO: + if (!(ctx->hflags & MIPS_HFLAG_64)) + generate_exception(ctx, EXCP_RI); gen_cl(ctx, op1, rd, rs); break; #endif @@ -5491,9 +5499,13 @@ static void decode_opc (CPUState *env, DisasContext *ctx) #ifdef TARGET_MIPS64 case OPC_DEXTM ... OPC_DEXT: case OPC_DINSM ... OPC_DINS: + if (!(ctx->hflags & MIPS_HFLAG_64)) + generate_exception(ctx, EXCP_RI); gen_bitops(ctx, op1, rt, rs, sa, rd); break; case OPC_DBSHFL: + if (!(ctx->hflags & MIPS_HFLAG_64)) + generate_exception(ctx, EXCP_RI); op2 = MASK_DBSHFL(ctx->opcode); switch (op2) { case OPC_DSBH: @@ -5732,9 +5744,13 @@ static void decode_opc (CPUState *env, DisasContext *ctx) case OPC_LD: case OPC_SCD: case OPC_SD: + if (!(ctx->hflags & MIPS_HFLAG_64)) + generate_exception(ctx, EXCP_RI); gen_ldst(ctx, op, rt, rs, imm); break; case OPC_DADDI ... OPC_DADDIU: + if (!(ctx->hflags & MIPS_HFLAG_64)) + generate_exception(ctx, EXCP_RI); gen_arith_imm(ctx, op, rt, rs, imm); break; #endif @@ -6072,11 +6088,14 @@ void cpu_reset (CPUMIPSState *env) /* If the exception was raised from a delay slot, * come back to the jump. */ env->CP0_ErrorEPC = env->PC - 4; - env->hflags &= ~MIPS_HFLAG_BMASK; } else { env->CP0_ErrorEPC = env->PC; } +#ifdef TARGET_MIPS64 + env->hflags = MIPS_HFLAG_64; +#else env->hflags = 0; +#endif env->PC = (int32_t)0xBFC00000; env->CP0_Wired = 0; /* SMP not implemented */ -- cgit v1.2.1