Hi, According to the MIPS64 manual, the 64-bit instructions should be decoded when: - the CPU is not in user mode - the CPU is in user mode, and PX and/or UX bits are set. Otherwise those instructions must generate a reserved instruction exception.
The patch below implements that. It also moves the decoding of the LWU instruction in a #ifdef TARGET_MIPS64 #erndif block, as it is a MIPS64 instruction only. Cheers, Aurelien Index: target-mips/cpu.h =================================================================== RCS file: /sources/qemu/qemu/target-mips/cpu.h,v retrieving revision 1.35 diff -u -d -p -r1.35 cpu.h --- target-mips/cpu.h 23 May 2007 08:24:25 -0000 1.35 +++ target-mips/cpu.h 28 May 2007 17:44:21 -0000 @@ -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 Index: target-mips/helper.c =================================================================== RCS file: /sources/qemu/qemu/target-mips/helper.c,v retrieving revision 1.41 diff -u -d -p -r1.41 helper.c --- target-mips/helper.c 23 May 2007 08:24:25 -0000 1.41 +++ target-mips/helper.c 28 May 2007 17:44:21 -0000 @@ -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; Index: target-mips/op.c =================================================================== RCS file: /sources/qemu/qemu/target-mips/op.c,v retrieving revision 1.63 diff -u -d -p -r1.63 op.c --- target-mips/op.c 28 May 2007 17:03:27 -0000 1.63 +++ target-mips/op.c 28 May 2007 17:44:21 -0000 @@ -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; Index: target-mips/translate.c =================================================================== RCS file: /sources/qemu/qemu/target-mips/translate.c,v retrieving revision 1.88 diff -u -d -p -r1.88 translate.c --- target-mips/translate.c 28 May 2007 17:03:28 -0000 1.88 +++ target-mips/translate.c 28 May 2007 17:44:22 -0000 @@ -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, */ 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, 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, D 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, D 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, D #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, D 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 */ -- .''`. Aurelien Jarno | GPG: 1024D/F1BCDB73 : :' : Debian developer | Electrical Engineer `. `' [EMAIL PROTECTED] | [EMAIL PROTECTED] `- people.debian.org/~aurel32 | www.aurel32.net