Check for R2 instructions, and throw RI if we don't emulate R2.

git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2921 c046a42c-6fe2-441c-8c8c-71466251a162
master
ths 2007-06-02 00:25:12 +00:00
parent 2538deb292
commit 3a95e3a7d9
1 changed files with 50 additions and 18 deletions

View File

@ -732,6 +732,14 @@ void check_cp1_registers(DisasContext *ctx, int regs)
generate_exception(ctx, EXCP_RI); generate_exception(ctx, EXCP_RI);
} }
/* This code generates a "reserved instruction" exception if the
CPU is not a MIPS R2 (or higher) 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) #if defined(CONFIG_USER_ONLY)
#define op_ldst(name) gen_op_##name##_raw() #define op_ldst(name) gen_op_##name##_raw()
#define OP_LD_TABLE(width) #define OP_LD_TABLE(width)
@ -1866,7 +1874,7 @@ fail:
} }
/* CP0 (MMU and control) */ /* 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"; const char *rn = "invalid";
@ -2000,6 +2008,7 @@ static void gen_mfc0 (DisasContext *ctx, int reg, int sel)
rn = "PageMask"; rn = "PageMask";
break; break;
case 1: case 1:
check_mips_r2(env, ctx);
gen_op_mfc0_pagegrain(); gen_op_mfc0_pagegrain();
rn = "PageGrain"; rn = "PageGrain";
break; break;
@ -2040,6 +2049,7 @@ static void gen_mfc0 (DisasContext *ctx, int reg, int sel)
case 7: case 7:
switch (sel) { switch (sel) {
case 0: case 0:
check_mips_r2(env, ctx);
gen_op_mfc0_hwrena(); gen_op_mfc0_hwrena();
rn = "HWREna"; rn = "HWREna";
break; break;
@ -2096,14 +2106,17 @@ static void gen_mfc0 (DisasContext *ctx, int reg, int sel)
rn = "Status"; rn = "Status";
break; break;
case 1: case 1:
check_mips_r2(env, ctx);
gen_op_mfc0_intctl(); gen_op_mfc0_intctl();
rn = "IntCtl"; rn = "IntCtl";
break; break;
case 2: case 2:
check_mips_r2(env, ctx);
gen_op_mfc0_srsctl(); gen_op_mfc0_srsctl();
rn = "SRSCtl"; rn = "SRSCtl";
break; break;
case 3: case 3:
check_mips_r2(env, ctx);
gen_op_mfc0_srsmap(); gen_op_mfc0_srsmap();
rn = "SRSMap"; rn = "SRSMap";
break; break;
@ -2138,6 +2151,7 @@ static void gen_mfc0 (DisasContext *ctx, int reg, int sel)
rn = "PRid"; rn = "PRid";
break; break;
case 1: case 1:
check_mips_r2(env, ctx);
gen_op_mfc0_ebase(); gen_op_mfc0_ebase();
rn = "EBase"; rn = "EBase";
break; break;
@ -2402,7 +2416,7 @@ die:
generate_exception(ctx, EXCP_RI); 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"; const char *rn = "invalid";
@ -2536,6 +2550,7 @@ static void gen_mtc0 (DisasContext *ctx, int reg, int sel)
rn = "PageMask"; rn = "PageMask";
break; break;
case 1: case 1:
check_mips_r2(env, ctx);
gen_op_mtc0_pagegrain(); gen_op_mtc0_pagegrain();
rn = "PageGrain"; rn = "PageGrain";
break; break;
@ -2576,6 +2591,7 @@ static void gen_mtc0 (DisasContext *ctx, int reg, int sel)
case 7: case 7:
switch (sel) { switch (sel) {
case 0: case 0:
check_mips_r2(env, ctx);
gen_op_mtc0_hwrena(); gen_op_mtc0_hwrena();
rn = "HWREna"; rn = "HWREna";
break; break;
@ -2633,18 +2649,21 @@ static void gen_mtc0 (DisasContext *ctx, int reg, int sel)
rn = "Status"; rn = "Status";
break; break;
case 1: case 1:
check_mips_r2(env, ctx);
gen_op_mtc0_intctl(); gen_op_mtc0_intctl();
/* 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;
rn = "IntCtl"; rn = "IntCtl";
break; break;
case 2: case 2:
check_mips_r2(env, ctx);
gen_op_mtc0_srsctl(); gen_op_mtc0_srsctl();
/* 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;
rn = "SRSCtl"; rn = "SRSCtl";
break; break;
case 3: case 3:
check_mips_r2(env, ctx);
gen_op_mtc0_srsmap(); gen_op_mtc0_srsmap();
/* 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;
@ -2683,6 +2702,7 @@ static void gen_mtc0 (DisasContext *ctx, int reg, int sel)
rn = "PRid"; rn = "PRid";
break; break;
case 1: case 1:
check_mips_r2(env, ctx);
gen_op_mtc0_ebase(); gen_op_mtc0_ebase();
rn = "EBase"; rn = "EBase";
break; break;
@ -2970,7 +2990,7 @@ die:
} }
#ifdef TARGET_MIPS64 #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"; const char *rn = "invalid";
@ -3104,6 +3124,7 @@ static void gen_dmfc0 (DisasContext *ctx, int reg, int sel)
rn = "PageMask"; rn = "PageMask";
break; break;
case 1: case 1:
check_mips_r2(env, ctx);
gen_op_mfc0_pagegrain(); gen_op_mfc0_pagegrain();
rn = "PageGrain"; rn = "PageGrain";
break; break;
@ -3144,6 +3165,7 @@ static void gen_dmfc0 (DisasContext *ctx, int reg, int sel)
case 7: case 7:
switch (sel) { switch (sel) {
case 0: case 0:
check_mips_r2(env, ctx);
gen_op_mfc0_hwrena(); gen_op_mfc0_hwrena();
rn = "HWREna"; rn = "HWREna";
break; break;
@ -3200,14 +3222,17 @@ static void gen_dmfc0 (DisasContext *ctx, int reg, int sel)
rn = "Status"; rn = "Status";
break; break;
case 1: case 1:
check_mips_r2(env, ctx);
gen_op_mfc0_intctl(); gen_op_mfc0_intctl();
rn = "IntCtl"; rn = "IntCtl";
break; break;
case 2: case 2:
check_mips_r2(env, ctx);
gen_op_mfc0_srsctl(); gen_op_mfc0_srsctl();
rn = "SRSCtl"; rn = "SRSCtl";
break; break;
case 3: case 3:
check_mips_r2(env, ctx);
gen_op_mfc0_srsmap(); /* shadow registers */ gen_op_mfc0_srsmap(); /* shadow registers */
rn = "SRSMap"; rn = "SRSMap";
break; break;
@ -3242,6 +3267,7 @@ static void gen_dmfc0 (DisasContext *ctx, int reg, int sel)
rn = "PRid"; rn = "PRid";
break; break;
case 1: case 1:
check_mips_r2(env, ctx);
gen_op_mfc0_ebase(); gen_op_mfc0_ebase();
rn = "EBase"; rn = "EBase";
break; break;
@ -3497,7 +3523,7 @@ die:
generate_exception(ctx, EXCP_RI); 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"; const char *rn = "invalid";
@ -3631,6 +3657,7 @@ static void gen_dmtc0 (DisasContext *ctx, int reg, int sel)
rn = "PageMask"; rn = "PageMask";
break; break;
case 1: case 1:
check_mips_r2(env, ctx);
gen_op_mtc0_pagegrain(); gen_op_mtc0_pagegrain();
rn = "PageGrain"; rn = "PageGrain";
break; break;
@ -3671,6 +3698,7 @@ static void gen_dmtc0 (DisasContext *ctx, int reg, int sel)
case 7: case 7:
switch (sel) { switch (sel) {
case 0: case 0:
check_mips_r2(env, ctx);
gen_op_mtc0_hwrena(); gen_op_mtc0_hwrena();
rn = "HWREna"; rn = "HWREna";
break; break;
@ -3728,18 +3756,21 @@ static void gen_dmtc0 (DisasContext *ctx, int reg, int sel)
rn = "Status"; rn = "Status";
break; break;
case 1: case 1:
check_mips_r2(env, ctx);
gen_op_mtc0_intctl(); gen_op_mtc0_intctl();
/* 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;
rn = "IntCtl"; rn = "IntCtl";
break; break;
case 2: case 2:
check_mips_r2(env, ctx);
gen_op_mtc0_srsctl(); gen_op_mtc0_srsctl();
/* 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;
rn = "SRSCtl"; rn = "SRSCtl";
break; break;
case 3: case 3:
check_mips_r2(env, ctx);
gen_op_mtc0_srsmap(); gen_op_mtc0_srsmap();
/* 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;
@ -3778,6 +3809,7 @@ static void gen_dmtc0 (DisasContext *ctx, int reg, int sel)
rn = "PRid"; rn = "PRid";
break; break;
case 1: case 1:
check_mips_r2(env, ctx);
gen_op_mtc0_ebase(); gen_op_mtc0_ebase();
rn = "EBase"; rn = "EBase";
break; break;
@ -4064,13 +4096,13 @@ static void gen_cp0 (CPUState *env, DisasContext *ctx, uint32_t opc, int rt, int
/* Treat as NOP */ /* Treat as NOP */
return; return;
} }
gen_mfc0(ctx, rd, ctx->opcode & 0x7); gen_mfc0(env, ctx, rd, ctx->opcode & 0x7);
gen_op_store_T0_gpr(rt); gen_op_store_T0_gpr(rt);
opn = "mfc0"; opn = "mfc0";
break; break;
case OPC_MTC0: case OPC_MTC0:
GEN_LOAD_REG_TN(T0, rt); GEN_LOAD_REG_TN(T0, rt);
gen_mtc0(ctx, rd, ctx->opcode & 0x7); gen_mtc0(env, ctx, rd, ctx->opcode & 0x7);
opn = "mtc0"; opn = "mtc0";
break; break;
#ifdef TARGET_MIPS64 #ifdef TARGET_MIPS64
@ -4079,13 +4111,13 @@ static void gen_cp0 (CPUState *env, DisasContext *ctx, uint32_t opc, int rt, int
/* Treat as NOP */ /* Treat as NOP */
return; return;
} }
gen_dmfc0(ctx, rd, ctx->opcode & 0x7); gen_dmfc0(env, ctx, rd, ctx->opcode & 0x7);
gen_op_store_T0_gpr(rt); gen_op_store_T0_gpr(rt);
opn = "dmfc0"; opn = "dmfc0";
break; break;
case OPC_DMTC0: case OPC_DMTC0:
GEN_LOAD_REG_TN(T0, rt); GEN_LOAD_REG_TN(T0, rt);
gen_dmtc0(ctx, rd, ctx->opcode & 0x7); gen_dmtc0(env,ctx, rd, ctx->opcode & 0x7);
opn = "dmtc0"; opn = "dmtc0";
break; break;
#endif #endif
@ -5501,6 +5533,7 @@ static void decode_opc (CPUState *env, DisasContext *ctx)
} }
break; break;
case OPC_SPECIAL3: case OPC_SPECIAL3:
check_mips_r2(env, ctx);
op1 = MASK_SPECIAL3(ctx->opcode); op1 = MASK_SPECIAL3(ctx->opcode);
switch (op1) { switch (op1) {
case OPC_EXT: case OPC_EXT:
@ -5604,6 +5637,7 @@ static void decode_opc (CPUState *env, DisasContext *ctx)
gen_trap(ctx, op1, rs, -1, imm); gen_trap(ctx, op1, rs, -1, imm);
break; break;
case OPC_SYNCI: case OPC_SYNCI:
check_mips_r2(env, ctx);
/* treat as noop */ /* treat as noop */
break; break;
default: /* Invalid */ default: /* Invalid */
@ -5629,6 +5663,7 @@ static void decode_opc (CPUState *env, DisasContext *ctx)
gen_cp0(env, ctx, MASK_C0(ctx->opcode), rt, rd); gen_cp0(env, ctx, MASK_C0(ctx->opcode), rt, rd);
break; break;
case OPC_MFMC0: case OPC_MFMC0:
check_mips_r2(env, ctx);
op2 = MASK_MFMC0(ctx->opcode); op2 = MASK_MFMC0(ctx->opcode);
switch (op2) { switch (op2) {
case OPC_DI: case OPC_DI:
@ -5650,14 +5685,10 @@ static void decode_opc (CPUState *env, DisasContext *ctx)
break; break;
case OPC_RDPGPR: case OPC_RDPGPR:
case OPC_WRPGPR: case OPC_WRPGPR:
if ((env->CP0_Config0 & (0x7 << CP0C0_AR)) == (1 << CP0C0_AR)) { check_mips_r2(env, ctx);
/* Shadow registers not implemented. */ /* Shadow registers not implemented. */
GEN_LOAD_REG_TN(T0, rt); GEN_LOAD_REG_TN(T0, rt);
GEN_STORE_TN_REG(rd, T0); GEN_STORE_TN_REG(rd, T0);
} else {
MIPS_INVAL("shadow register move");
generate_exception(ctx, EXCP_RI);
}
break; break;
default: default:
MIPS_INVAL("cp0"); MIPS_INVAL("cp0");
@ -5710,6 +5741,9 @@ static void decode_opc (CPUState *env, DisasContext *ctx)
check_cp1_enabled(ctx); check_cp1_enabled(ctx);
op1 = MASK_CP1(ctx->opcode); op1 = MASK_CP1(ctx->opcode);
switch (op1) { switch (op1) {
case OPC_MFHC1:
case OPC_MTHC1:
check_mips_r2(env, ctx);
case OPC_MFC1: case OPC_MFC1:
case OPC_CFC1: case OPC_CFC1:
case OPC_MTC1: case OPC_MTC1:
@ -5718,8 +5752,6 @@ static void decode_opc (CPUState *env, DisasContext *ctx)
case OPC_DMFC1: case OPC_DMFC1:
case OPC_DMTC1: case OPC_DMTC1:
#endif #endif
case OPC_MFHC1:
case OPC_MTHC1:
gen_cp1(ctx, op1, rt, rd); gen_cp1(ctx, op1, rt, rd);
break; break;
case OPC_BC1: case OPC_BC1: