On Tue, May 29, 2007 at 12:15:01AM +0200, Aurelien Jarno wrote: > Hi, > > In the current implementation of the MIPS CPU, all instructions are > regarded as valid, being R1 or R2 instructions. > > This patch fixes that by generating a reserved instruction exception > when an R2 instructions is decoded on an R1 only CPU. > > Note that I have left the FPU code unchanged, as I don't know a lot > about it. I will do the same later, after reading the FPU part of the > manuals. >
As discussed on IRC, please find below a new version of the patch which uses an inline function instead of writting the if code each time. Index: target-mips/translate.c =================================================================== RCS file: /sources/qemu/qemu/target-mips/translate.c,v retrieving revision 1.89 diff -u -d -p -r1.89 translate.c --- target-mips/translate.c 28 May 2007 20:36:48 -0000 1.89 +++ target-mips/translate.c 29 May 2007 06:14:49 -0000 @@ -703,6 +703,14 @@ static inline void generate_exception (D generate_exception_err (ctx, excp, 0); } +/* This code generates a "reserved instruction" exception if the + CPU is not a MIPS R2 CPU. */ +static inline void check_mips_r2(CPUState *env, DisasContext *ctx) +{ + if ((env->CP0_Config0 & (0x7 << CP0C0_AR)) != (1 << CP0C0_AR)) + generate_exception(ctx, EXCP_RI); +} + #if defined(CONFIG_USER_ONLY) #define op_ldst(name) gen_op_##name##_raw() #define OP_LD_TABLE(width) @@ -1837,7 +1845,7 @@ fail: } /* CP0 (MMU and control) */ -static void gen_mfc0 (DisasContext *ctx, int reg, int sel) +static void gen_mfc0 (CPUState *env, DisasContext *ctx, int reg, int sel) { const char *rn = "invalid"; @@ -1971,6 +1979,7 @@ static void gen_mfc0 (DisasContext *ctx, rn = "PageMask"; break; case 1: + check_mips_r2(env, ctx); gen_op_mfc0_pagegrain(); rn = "PageGrain"; break; @@ -2011,6 +2020,7 @@ static void gen_mfc0 (DisasContext *ctx, case 7: switch (sel) { case 0: + check_mips_r2(env, ctx); gen_op_mfc0_hwrena(); rn = "HWREna"; break; @@ -2067,14 +2077,17 @@ static void gen_mfc0 (DisasContext *ctx, rn = "Status"; break; case 1: + check_mips_r2(env, ctx); gen_op_mfc0_intctl(); rn = "IntCtl"; break; case 2: + check_mips_r2(env, ctx); gen_op_mfc0_srsctl(); rn = "SRSCtl"; break; case 3: + check_mips_r2(env, ctx); gen_op_mfc0_srsmap(); rn = "SRSMap"; break; @@ -2109,6 +2122,7 @@ static void gen_mfc0 (DisasContext *ctx, rn = "PRid"; break; case 1: + check_mips_r2(env, ctx); gen_op_mfc0_ebase(); rn = "EBase"; break; @@ -2373,7 +2387,7 @@ die: generate_exception(ctx, EXCP_RI); } -static void gen_mtc0 (DisasContext *ctx, int reg, int sel) +static void gen_mtc0 (CPUState *env, DisasContext *ctx, int reg, int sel) { const char *rn = "invalid"; @@ -2507,6 +2521,7 @@ static void gen_mtc0 (DisasContext *ctx, rn = "PageMask"; break; case 1: + check_mips_r2(env, ctx); gen_op_mtc0_pagegrain(); rn = "PageGrain"; break; @@ -2547,6 +2562,7 @@ static void gen_mtc0 (DisasContext *ctx, case 7: switch (sel) { case 0: + check_mips_r2(env, ctx); gen_op_mtc0_hwrena(); rn = "HWREna"; break; @@ -2601,14 +2617,17 @@ static void gen_mtc0 (DisasContext *ctx, rn = "Status"; break; case 1: + check_mips_r2(env, ctx); gen_op_mtc0_intctl(); rn = "IntCtl"; break; case 2: + check_mips_r2(env, ctx); gen_op_mtc0_srsctl(); rn = "SRSCtl"; break; case 3: + check_mips_r2(env, ctx); gen_op_mtc0_srsmap(); rn = "SRSMap"; break; @@ -2647,6 +2666,7 @@ static void gen_mtc0 (DisasContext *ctx, rn = "PRid"; break; case 1: + check_mips_r2(env, ctx); gen_op_mtc0_ebase(); rn = "EBase"; break; @@ -2923,7 +2943,7 @@ die: } #ifdef TARGET_MIPS64 -static void gen_dmfc0 (DisasContext *ctx, int reg, int sel) +static void gen_dmfc0 (CPUState *env, DisasContext *ctx, int reg, int sel) { const char *rn = "invalid"; @@ -3057,6 +3077,7 @@ static void gen_dmfc0 (DisasContext *ctx rn = "PageMask"; break; case 1: + check_mips_r2(env, ctx); gen_op_mfc0_pagegrain(); rn = "PageGrain"; break; @@ -3097,6 +3118,7 @@ static void gen_dmfc0 (DisasContext *ctx case 7: switch (sel) { case 0: + check_mips_r2(env, ctx); gen_op_mfc0_hwrena(); rn = "HWREna"; break; @@ -3153,14 +3175,17 @@ static void gen_dmfc0 (DisasContext *ctx rn = "Status"; break; case 1: + check_mips_r2(env, ctx); gen_op_mfc0_intctl(); rn = "IntCtl"; break; case 2: + check_mips_r2(env, ctx); gen_op_mfc0_srsctl(); rn = "SRSCtl"; break; case 3: + check_mips_r2(env, ctx); gen_op_mfc0_srsmap(); /* shadow registers */ rn = "SRSMap"; break; @@ -3195,6 +3220,7 @@ static void gen_dmfc0 (DisasContext *ctx rn = "PRid"; break; case 1: + check_mips_r2(env, ctx); gen_op_mfc0_ebase(); rn = "EBase"; break; @@ -3450,7 +3476,7 @@ die: generate_exception(ctx, EXCP_RI); } -static void gen_dmtc0 (DisasContext *ctx, int reg, int sel) +static void gen_dmtc0 (CPUState *env, DisasContext *ctx, int reg, int sel) { const char *rn = "invalid"; @@ -3584,6 +3610,7 @@ static void gen_dmtc0 (DisasContext *ctx rn = "PageMask"; break; case 1: + check_mips_r2(env, ctx); gen_op_mtc0_pagegrain(); rn = "PageGrain"; break; @@ -3624,6 +3651,7 @@ static void gen_dmtc0 (DisasContext *ctx case 7: switch (sel) { case 0: + check_mips_r2(env, ctx); gen_op_mtc0_hwrena(); rn = "HWREna"; break; @@ -3678,14 +3706,17 @@ static void gen_dmtc0 (DisasContext *ctx rn = "Status"; break; case 1: + check_mips_r2(env, ctx); gen_op_mtc0_intctl(); rn = "IntCtl"; break; case 2: + check_mips_r2(env, ctx); gen_op_mtc0_srsctl(); rn = "SRSCtl"; break; case 3: + check_mips_r2(env, ctx); gen_op_mtc0_srsmap(); rn = "SRSMap"; break; @@ -3724,6 +3755,7 @@ static void gen_dmtc0 (DisasContext *ctx rn = "PRid"; break; case 1: + check_mips_r2(env, ctx); gen_op_mtc0_ebase(); rn = "EBase"; break; @@ -4001,13 +4033,13 @@ static void gen_cp0 (CPUState *env, Disa /* Treat as NOP */ return; } - gen_mfc0(ctx, rd, ctx->opcode & 0x7); + gen_mfc0(env, ctx, rd, ctx->opcode & 0x7); gen_op_store_T0_gpr(rt); opn = "mfc0"; break; case OPC_MTC0: GEN_LOAD_REG_TN(T0, rt); - gen_mtc0(ctx, rd, ctx->opcode & 0x7); + gen_mtc0(env, ctx, rd, ctx->opcode & 0x7); opn = "mtc0"; break; #ifdef TARGET_MIPS64 @@ -4016,13 +4048,13 @@ static void gen_cp0 (CPUState *env, Disa /* Treat as NOP */ return; } - gen_dmfc0(ctx, rd, ctx->opcode & 0x7); + gen_dmfc0(env, ctx, rd, ctx->opcode & 0x7); gen_op_store_T0_gpr(rt); opn = "dmfc0"; break; case OPC_DMTC0: GEN_LOAD_REG_TN(T0, rt); - gen_dmtc0(ctx, rd, ctx->opcode & 0x7); + gen_dmtc0(env,ctx, rd, ctx->opcode & 0x7); opn = "dmtc0"; break; #endif @@ -5438,6 +5470,7 @@ static void decode_opc (CPUState *env, D } break; case OPC_SPECIAL3: + check_mips_r2(env, ctx); op1 = MASK_SPECIAL3(ctx->opcode); switch (op1) { case OPC_EXT: @@ -5541,6 +5574,7 @@ static void decode_opc (CPUState *env, D gen_trap(ctx, op1, rs, -1, imm); break; case OPC_SYNCI: + check_mips_r2(env, ctx); /* treat as noop */ break; default: /* Invalid */ @@ -5566,6 +5600,7 @@ static void decode_opc (CPUState *env, D gen_cp0(env, ctx, MASK_C0(ctx->opcode), rt, rd); break; case OPC_MFMC0: + check_mips_r2(env, ctx); op2 = MASK_MFMC0(ctx->opcode); switch (op2) { case OPC_DI: @@ -5587,14 +5622,10 @@ static void decode_opc (CPUState *env, D break; case OPC_RDPGPR: case OPC_WRPGPR: - if ((env->CP0_Config0 & (0x7 << CP0C0_AR)) == (1 << CP0C0_AR)) { - /* Shadow registers not implemented. */ - GEN_LOAD_REG_TN(T0, rt); - GEN_STORE_TN_REG(rd, T0); - } else { - MIPS_INVAL("shadow register move"); - generate_exception(ctx, EXCP_RI); - } + check_mips_r2(env, ctx); + /* Shadow registers not implemented. */ + GEN_LOAD_REG_TN(T0, rt); + GEN_STORE_TN_REG(rd, T0); break; default: MIPS_INVAL("cp0"); @@ -5647,6 +5678,9 @@ static void decode_opc (CPUState *env, D gen_op_cp1_enabled(); op1 = MASK_CP1(ctx->opcode); switch (op1) { + case OPC_MFHC1: + case OPC_MTHC1: + check_mips_r2(env, ctx); case OPC_MFC1: case OPC_CFC1: case OPC_MTC1: @@ -5655,8 +5689,6 @@ static void decode_opc (CPUState *env, D case OPC_DMFC1: case OPC_DMTC1: #endif - case OPC_MFHC1: - case OPC_MTHC1: gen_cp1(ctx, op1, rt, rd); break; case OPC_BC1: -- .''`. Aurelien Jarno | GPG: 1024D/F1BCDB73 : :' : Debian developer | Electrical Engineer `. `' [EMAIL PROTECTED] | [EMAIL PROTECTED] `- people.debian.org/~aurel32 | www.aurel32.net