Per-CPU instruction decoding implementation, by Aurelien Jarno.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3228 c046a42c-6fe2-441c-8c8c-71466251a162
diff --git a/target-mips/cpu.h b/target-mips/cpu.h
index f8b4b18..f8299ad 100644
--- a/target-mips/cpu.h
+++ b/target-mips/cpu.h
@@ -441,6 +441,7 @@
int CCRes; /* Cycle count resolution/divisor */
uint32_t CP0_Status_rw_bitmask; /* Read/write bits in CP0_Status */
uint32_t CP0_TCStatus_rw_bitmask; /* Read/write bits in CP0_TCStatus */
+ int insn_flags; /* Supported instruction set */
#ifdef CONFIG_USER_ONLY
target_ulong tls_value;
diff --git a/target-mips/helper.c b/target-mips/helper.c
index 6310d68..d0e5b1d 100644
--- a/target-mips/helper.c
+++ b/target-mips/helper.c
@@ -369,8 +369,7 @@
}
enter_debug_mode:
env->hflags |= MIPS_HFLAG_DM;
- if ((env->CP0_Config0 & (0x3 << CP0C0_AT)))
- env->hflags |= MIPS_HFLAG_64;
+ env->hflags |= MIPS_HFLAG_64;
env->hflags &= ~MIPS_HFLAG_UM;
/* EJTAG probe trap enable is not implemented... */
if (!(env->CP0_Status & (1 << CP0St_EXL)))
@@ -396,8 +395,7 @@
env->CP0_ErrorEPC = env->PC[env->current_tc];
}
env->CP0_Status |= (1 << CP0St_ERL) | (1 << CP0St_BEV);
- if ((env->CP0_Config0 & (0x3 << CP0C0_AT)))
- env->hflags |= MIPS_HFLAG_64;
+ env->hflags |= MIPS_HFLAG_64;
env->hflags &= ~MIPS_HFLAG_UM;
if (!(env->CP0_Status & (1 << CP0St_EXL)))
env->CP0_Cause &= ~(1 << CP0Ca_BD);
@@ -499,8 +497,7 @@
env->CP0_Cause &= ~(1 << CP0Ca_BD);
}
env->CP0_Status |= (1 << CP0St_EXL);
- if ((env->CP0_Config0 & (0x3 << CP0C0_AT)))
- env->hflags |= MIPS_HFLAG_64;
+ env->hflags |= MIPS_HFLAG_64;
env->hflags &= ~MIPS_HFLAG_UM;
}
env->hflags &= ~MIPS_HFLAG_BMASK;
diff --git a/target-mips/mips-defs.h b/target-mips/mips-defs.h
index 6f012a9..a796c7e 100644
--- a/target-mips/mips-defs.h
+++ b/target-mips/mips-defs.h
@@ -14,6 +14,41 @@
#define TARGET_LONG_BITS 32
#endif
+/* Masks used to mark instructions to indicate which ISA level they
+ were introduced in. */
+#define ISA_MIPS1 0x00000001
+#define ISA_MIPS2 0x00000002
+#define ISA_MIPS3 0x00000004
+#define ISA_MIPS4 0x00000008
+#define ISA_MIPS5 0x00000010
+#define ISA_MIPS32 0x00000020
+#define ISA_MIPS32R2 0x00000040
+#define ISA_MIPS64 0x00000080
+#define ISA_MIPS64R2 0x00000100
+
+/* MIPS ASE */
+#define ASE_MIPS16 0x00001000
+#define ASE_MIPS3D 0x00002000
+#define ASE_MDMX 0x00004000
+#define ASE_DSP 0x00008000
+#define ASE_DSPR2 0x00010000
+
+/* Chip specific instructions. */
+/* Currently void */
+
+/* MIPS CPU defines. */
+#define CPU_MIPS1 (ISA_MIPS1)
+#define CPU_MIPS2 (CPU_MIPS1 | ISA_MIPS2)
+#define CPU_MIPS3 (CPU_MIPS2 | ISA_MIPS3)
+#define CPU_MIPS4 (CPU_MIPS3 | ISA_MIPS4)
+#define CPU_MIPS5 (CPU_MIPS4 | ISA_MIPS5)
+
+#define CPU_MIPS32 (CPU_MIPS2 | ISA_MIPS32)
+#define CPU_MIPS64 (CPU_MIPS5 | CPU_MIPS32 | ISA_MIPS64)
+
+#define CPU_MIPS32R2 (CPU_MIPS32 | ISA_MIPS32R2)
+#define CPU_MIPS64R2 (CPU_MIPS64 | CPU_MIPS32R2 | ISA_MIPS64R2)
+
/* Strictly follow the architecture standard:
- Disallow "special" instruction handling for PMON/SPIM.
Note that we still maintain Count/Compare to match the host clock. */
diff --git a/target-mips/op.c b/target-mips/op.c
index 8d4c7d4..dd90163 100644
--- a/target-mips/op.c
+++ b/target-mips/op.c
@@ -1847,10 +1847,9 @@
(val & (1 << CP0St_UM)))
env->hflags |= MIPS_HFLAG_UM;
#ifdef TARGET_MIPS64
- if (!(env->CP0_Config0 & (0x3 << CP0C0_AT)) ||
- ((env->hflags & MIPS_HFLAG_UM) &&
+ if ((env->hflags & MIPS_HFLAG_UM) &&
!(val & (1 << CP0St_PX)) &&
- !(val & (1 << CP0St_UX))))
+ !(val & (1 << CP0St_UX)))
env->hflags &= ~MIPS_HFLAG_64;
#endif
if (val & (1 << CP0St_CU1))
@@ -1906,7 +1905,7 @@
{
uint32_t mask = 0x00C00300;
- if ((env->CP0_Config0 & (0x7 << CP0C0_AR)) == (1 << CP0C0_AR))
+ if (env->insn_flags & ISA_MIPS32R2)
mask |= 1 << CP0Ca_DC;
env->CP0_Cause = (env->CP0_Cause & ~mask) | (T0 & mask);
@@ -3014,10 +3013,9 @@
(env->CP0_Status & (1 << CP0St_UM)))
env->hflags |= MIPS_HFLAG_UM;
#ifdef TARGET_MIPS64
- if (!(env->CP0_Config0 & (0x3 << CP0C0_AT)) ||
- ((env->hflags & MIPS_HFLAG_UM) &&
+ if ((env->hflags & MIPS_HFLAG_UM) &&
!(env->CP0_Status & (1 << CP0St_PX)) &&
- !(env->CP0_Status & (1 << CP0St_UX))))
+ !(env->CP0_Status & (1 << CP0St_UX)))
env->hflags &= ~MIPS_HFLAG_64;
#endif
if (loglevel & CPU_LOG_EXEC)
@@ -3038,10 +3036,9 @@
(env->CP0_Status & (1 << CP0St_UM)))
env->hflags |= MIPS_HFLAG_UM;
#ifdef TARGET_MIPS64
- if (!(env->CP0_Config0 & (0x3 << CP0C0_AT)) ||
- ((env->hflags & MIPS_HFLAG_UM) &&
+ if ((env->hflags & MIPS_HFLAG_UM) &&
!(env->CP0_Status & (1 << CP0St_PX)) &&
- !(env->CP0_Status & (1 << CP0St_UX))))
+ !(env->CP0_Status & (1 << CP0St_UX)))
env->hflags &= ~MIPS_HFLAG_64;
#endif
if (loglevel & CPU_LOG_EXEC)
diff --git a/target-mips/translate.c b/target-mips/translate.c
index ddffc0f..004b2f7 100644
--- a/target-mips/translate.c
+++ b/target-mips/translate.c
@@ -142,7 +142,7 @@
OPC_SRL = 0x02 | OPC_SPECIAL, /* also ROTR */
OPC_SRA = 0x03 | OPC_SPECIAL,
OPC_SLLV = 0x04 | OPC_SPECIAL,
- OPC_SRLV = 0x06 | OPC_SPECIAL,
+ OPC_SRLV = 0x06 | OPC_SPECIAL, /* also ROTRV */
OPC_SRAV = 0x07 | OPC_SPECIAL,
OPC_DSLLV = 0x14 | OPC_SPECIAL,
OPC_DSRLV = 0x16 | OPC_SPECIAL, /* also DROTRV */
@@ -761,10 +761,10 @@
}
/* 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)
+ CPU does not support the instruction set corresponding to flags. */
+static inline void check_insn(CPUState *env, DisasContext *ctx, int flags)
{
- if ((env->CP0_Config0 & (0x7 << CP0C0_AR)) < (1 << CP0C0_AR))
+ if (unlikely(!(env->insn_flags & flags)))
generate_exception(ctx, EXCP_RI);
}
@@ -776,6 +776,14 @@
generate_exception(ctx, EXCP_RI);
}
+/* This code generates a "reserved instruction" exception if 64-bit
+ instructions are not enabled. */
+static inline void check_mips_64(DisasContext *ctx)
+{
+ if (!(ctx->hflags & MIPS_HFLAG_64))
+ generate_exception(ctx, EXCP_RI);
+}
+
#if defined(CONFIG_USER_ONLY)
#define op_ldst(name) gen_op_##name##_raw()
#define OP_LD_TABLE(width)
@@ -1024,8 +1032,8 @@
}
/* Arithmetic with immediate operand */
-static void gen_arith_imm (DisasContext *ctx, uint32_t opc, int rt,
- int rs, int16_t imm)
+static void gen_arith_imm (CPUState *env, DisasContext *ctx, uint32_t opc,
+ int rt, int rs, int16_t imm)
{
target_ulong uimm;
const char *opn = "imm arith";
@@ -1132,8 +1140,14 @@
opn = "srl";
break;
case 1:
- gen_op_rotr();
- opn = "rotr";
+ /* rotr is decoded as srl on non-R2 CPUs */
+ if (env->insn_flags & ISA_MIPS32R2) {
+ gen_op_rotr();
+ opn = "rotr";
+ } else {
+ gen_op_srl();
+ opn = "srl";
+ }
break;
default:
MIPS_INVAL("invalid srl flag");
@@ -1157,8 +1171,14 @@
opn = "dsrl";
break;
case 1:
- gen_op_drotr();
- opn = "drotr";
+ /* drotr is decoded as dsrl on non-R2 CPUs */
+ if (env->insn_flags & ISA_MIPS32R2) {
+ gen_op_drotr();
+ opn = "drotr";
+ } else {
+ gen_op_dsrl();
+ opn = "dsrl";
+ }
break;
default:
MIPS_INVAL("invalid dsrl flag");
@@ -1181,8 +1201,14 @@
opn = "dsrl32";
break;
case 1:
- gen_op_drotr32();
- opn = "drotr32";
+ /* drotr32 is decoded as dsrl32 on non-R2 CPUs */
+ if (env->insn_flags & ISA_MIPS32R2) {
+ gen_op_drotr32();
+ opn = "drotr32";
+ } else {
+ gen_op_dsrl32();
+ opn = "dsrl32";
+ }
break;
default:
MIPS_INVAL("invalid dsrl32 flag");
@@ -1201,7 +1227,7 @@
}
/* Arithmetic */
-static void gen_arith (DisasContext *ctx, uint32_t opc,
+static void gen_arith (CPUState *env, DisasContext *ctx, uint32_t opc,
int rd, int rs, int rt)
{
const char *opn = "arith";
@@ -1305,8 +1331,14 @@
opn = "srlv";
break;
case 1:
- gen_op_rotrv();
- opn = "rotrv";
+ /* rotrv is decoded as srlv on non-R2 CPUs */
+ if (env->insn_flags & ISA_MIPS32R2) {
+ gen_op_rotrv();
+ opn = "rotrv";
+ } else {
+ gen_op_srlv();
+ opn = "srlv";
+ }
break;
default:
MIPS_INVAL("invalid srlv flag");
@@ -1330,8 +1362,14 @@
opn = "dsrlv";
break;
case 1:
- gen_op_drotrv();
- opn = "drotrv";
+ /* drotrv is decoded as dsrlv on non-R2 CPUs */
+ if (env->insn_flags & ISA_MIPS32R2) {
+ gen_op_drotrv();
+ opn = "drotrv";
+ } else {
+ gen_op_dsrlv();
+ opn = "dsrlv";
+ }
break;
default:
MIPS_INVAL("invalid dsrlv flag");
@@ -1910,6 +1948,9 @@
{
const char *rn = "invalid";
+ if (sel != 0)
+ check_insn(env, ctx, ISA_MIPS32);
+
switch (reg) {
case 0:
switch (sel) {
@@ -2057,7 +2098,7 @@
rn = "PageMask";
break;
case 1:
- check_mips_r2(env, ctx);
+ check_insn(env, ctx, ISA_MIPS32R2);
gen_op_mfc0_pagegrain();
rn = "PageGrain";
break;
@@ -2072,22 +2113,27 @@
rn = "Wired";
break;
case 1:
+ check_insn(env, ctx, ISA_MIPS32R2);
gen_op_mfc0_srsconf0();
rn = "SRSConf0";
break;
case 2:
+ check_insn(env, ctx, ISA_MIPS32R2);
gen_op_mfc0_srsconf1();
rn = "SRSConf1";
break;
case 3:
+ check_insn(env, ctx, ISA_MIPS32R2);
gen_op_mfc0_srsconf2();
rn = "SRSConf2";
break;
case 4:
+ check_insn(env, ctx, ISA_MIPS32R2);
gen_op_mfc0_srsconf3();
rn = "SRSConf3";
break;
case 5:
+ check_insn(env, ctx, ISA_MIPS32R2);
gen_op_mfc0_srsconf4();
rn = "SRSConf4";
break;
@@ -2098,7 +2144,7 @@
case 7:
switch (sel) {
case 0:
- check_mips_r2(env, ctx);
+ check_insn(env, ctx, ISA_MIPS32R2);
gen_op_mfc0_hwrena();
rn = "HWREna";
break;
@@ -2155,17 +2201,17 @@
rn = "Status";
break;
case 1:
- check_mips_r2(env, ctx);
+ check_insn(env, ctx, ISA_MIPS32R2);
gen_op_mfc0_intctl();
rn = "IntCtl";
break;
case 2:
- check_mips_r2(env, ctx);
+ check_insn(env, ctx, ISA_MIPS32R2);
gen_op_mfc0_srsctl();
rn = "SRSCtl";
break;
case 3:
- check_mips_r2(env, ctx);
+ check_insn(env, ctx, ISA_MIPS32R2);
gen_op_mfc0_srsmap();
rn = "SRSMap";
break;
@@ -2200,7 +2246,7 @@
rn = "PRid";
break;
case 1:
- check_mips_r2(env, ctx);
+ check_insn(env, ctx, ISA_MIPS32R2);
gen_op_mfc0_ebase();
rn = "EBase";
break;
@@ -2274,8 +2320,7 @@
switch (sel) {
case 0:
#ifdef TARGET_MIPS64
- if (!(ctx->hflags & MIPS_HFLAG_64))
- goto die;
+ check_insn(env, ctx, ISA_MIPS3);
gen_op_mfc0_xcontext();
rn = "XContext";
break;
@@ -2471,6 +2516,9 @@
{
const char *rn = "invalid";
+ if (sel != 0)
+ check_insn(env, ctx, ISA_MIPS32);
+
switch (reg) {
case 0:
switch (sel) {
@@ -2618,7 +2666,7 @@
rn = "PageMask";
break;
case 1:
- check_mips_r2(env, ctx);
+ check_insn(env, ctx, ISA_MIPS32R2);
gen_op_mtc0_pagegrain();
rn = "PageGrain";
break;
@@ -2633,22 +2681,27 @@
rn = "Wired";
break;
case 1:
+ check_insn(env, ctx, ISA_MIPS32R2);
gen_op_mtc0_srsconf0();
rn = "SRSConf0";
break;
case 2:
+ check_insn(env, ctx, ISA_MIPS32R2);
gen_op_mtc0_srsconf1();
rn = "SRSConf1";
break;
case 3:
+ check_insn(env, ctx, ISA_MIPS32R2);
gen_op_mtc0_srsconf2();
rn = "SRSConf2";
break;
case 4:
+ check_insn(env, ctx, ISA_MIPS32R2);
gen_op_mtc0_srsconf3();
rn = "SRSConf3";
break;
case 5:
+ check_insn(env, ctx, ISA_MIPS32R2);
gen_op_mtc0_srsconf4();
rn = "SRSConf4";
break;
@@ -2659,7 +2712,7 @@
case 7:
switch (sel) {
case 0:
- check_mips_r2(env, ctx);
+ check_insn(env, ctx, ISA_MIPS32R2);
gen_op_mtc0_hwrena();
rn = "HWREna";
break;
@@ -2717,21 +2770,21 @@
rn = "Status";
break;
case 1:
- check_mips_r2(env, ctx);
+ check_insn(env, ctx, ISA_MIPS32R2);
gen_op_mtc0_intctl();
/* Stop translation as we may have switched the execution mode */
ctx->bstate = BS_STOP;
rn = "IntCtl";
break;
case 2:
- check_mips_r2(env, ctx);
+ check_insn(env, ctx, ISA_MIPS32R2);
gen_op_mtc0_srsctl();
/* Stop translation as we may have switched the execution mode */
ctx->bstate = BS_STOP;
rn = "SRSCtl";
break;
case 3:
- check_mips_r2(env, ctx);
+ check_insn(env, ctx, ISA_MIPS32R2);
gen_op_mtc0_srsmap();
/* Stop translation as we may have switched the execution mode */
ctx->bstate = BS_STOP;
@@ -2770,7 +2823,7 @@
rn = "PRid";
break;
case 1:
- check_mips_r2(env, ctx);
+ check_insn(env, ctx, ISA_MIPS32R2);
gen_op_mtc0_ebase();
rn = "EBase";
break;
@@ -2849,8 +2902,7 @@
switch (sel) {
case 0:
#ifdef TARGET_MIPS64
- if (!(ctx->hflags & MIPS_HFLAG_64))
- goto die;
+ check_insn(env, ctx, ISA_MIPS3);
gen_op_mtc0_xcontext();
rn = "XContext";
break;
@@ -3064,6 +3116,9 @@
{
const char *rn = "invalid";
+ if (sel != 0)
+ check_insn(env, ctx, ISA_MIPS64);
+
switch (reg) {
case 0:
switch (sel) {
@@ -3211,7 +3266,7 @@
rn = "PageMask";
break;
case 1:
- check_mips_r2(env, ctx);
+ check_insn(env, ctx, ISA_MIPS32R2);
gen_op_mfc0_pagegrain();
rn = "PageGrain";
break;
@@ -3226,22 +3281,27 @@
rn = "Wired";
break;
case 1:
+ check_insn(env, ctx, ISA_MIPS32R2);
gen_op_mfc0_srsconf0();
rn = "SRSConf0";
break;
case 2:
+ check_insn(env, ctx, ISA_MIPS32R2);
gen_op_mfc0_srsconf1();
rn = "SRSConf1";
break;
case 3:
+ check_insn(env, ctx, ISA_MIPS32R2);
gen_op_mfc0_srsconf2();
rn = "SRSConf2";
break;
case 4:
+ check_insn(env, ctx, ISA_MIPS32R2);
gen_op_mfc0_srsconf3();
rn = "SRSConf3";
break;
case 5:
+ check_insn(env, ctx, ISA_MIPS32R2);
gen_op_mfc0_srsconf4();
rn = "SRSConf4";
break;
@@ -3252,7 +3312,7 @@
case 7:
switch (sel) {
case 0:
- check_mips_r2(env, ctx);
+ check_insn(env, ctx, ISA_MIPS32R2);
gen_op_mfc0_hwrena();
rn = "HWREna";
break;
@@ -3309,17 +3369,17 @@
rn = "Status";
break;
case 1:
- check_mips_r2(env, ctx);
+ check_insn(env, ctx, ISA_MIPS32R2);
gen_op_mfc0_intctl();
rn = "IntCtl";
break;
case 2:
- check_mips_r2(env, ctx);
+ check_insn(env, ctx, ISA_MIPS32R2);
gen_op_mfc0_srsctl();
rn = "SRSCtl";
break;
case 3:
- check_mips_r2(env, ctx);
+ check_insn(env, ctx, ISA_MIPS32R2);
gen_op_mfc0_srsmap();
rn = "SRSMap";
break;
@@ -3354,7 +3414,7 @@
rn = "PRid";
break;
case 1:
- check_mips_r2(env, ctx);
+ check_insn(env, ctx, ISA_MIPS32R2);
gen_op_mfc0_ebase();
rn = "EBase";
break;
@@ -3418,6 +3478,7 @@
case 20:
switch (sel) {
case 0:
+ check_insn(env, ctx, ISA_MIPS3);
gen_op_dmfc0_xcontext();
rn = "XContext";
break;
@@ -3612,6 +3673,9 @@
{
const char *rn = "invalid";
+ if (sel != 0)
+ check_insn(env, ctx, ISA_MIPS64);
+
switch (reg) {
case 0:
switch (sel) {
@@ -3759,7 +3823,7 @@
rn = "PageMask";
break;
case 1:
- check_mips_r2(env, ctx);
+ check_insn(env, ctx, ISA_MIPS32R2);
gen_op_mtc0_pagegrain();
rn = "PageGrain";
break;
@@ -3774,22 +3838,27 @@
rn = "Wired";
break;
case 1:
+ check_insn(env, ctx, ISA_MIPS32R2);
gen_op_mtc0_srsconf0();
rn = "SRSConf0";
break;
case 2:
+ check_insn(env, ctx, ISA_MIPS32R2);
gen_op_mtc0_srsconf1();
rn = "SRSConf1";
break;
case 3:
+ check_insn(env, ctx, ISA_MIPS32R2);
gen_op_mtc0_srsconf2();
rn = "SRSConf2";
break;
case 4:
+ check_insn(env, ctx, ISA_MIPS32R2);
gen_op_mtc0_srsconf3();
rn = "SRSConf3";
break;
case 5:
+ check_insn(env, ctx, ISA_MIPS32R2);
gen_op_mtc0_srsconf4();
rn = "SRSConf4";
break;
@@ -3800,7 +3869,7 @@
case 7:
switch (sel) {
case 0:
- check_mips_r2(env, ctx);
+ check_insn(env, ctx, ISA_MIPS32R2);
gen_op_mtc0_hwrena();
rn = "HWREna";
break;
@@ -3858,21 +3927,21 @@
rn = "Status";
break;
case 1:
- check_mips_r2(env, ctx);
+ check_insn(env, ctx, ISA_MIPS32R2);
gen_op_mtc0_intctl();
/* Stop translation as we may have switched the execution mode */
ctx->bstate = BS_STOP;
rn = "IntCtl";
break;
case 2:
- check_mips_r2(env, ctx);
+ check_insn(env, ctx, ISA_MIPS32R2);
gen_op_mtc0_srsctl();
/* Stop translation as we may have switched the execution mode */
ctx->bstate = BS_STOP;
rn = "SRSCtl";
break;
case 3:
- check_mips_r2(env, ctx);
+ check_insn(env, ctx, ISA_MIPS32R2);
gen_op_mtc0_srsmap();
/* Stop translation as we may have switched the execution mode */
ctx->bstate = BS_STOP;
@@ -3911,7 +3980,7 @@
rn = "PRid";
break;
case 1:
- check_mips_r2(env, ctx);
+ check_insn(env, ctx, ISA_MIPS32R2);
gen_op_mtc0_ebase();
rn = "EBase";
break;
@@ -3980,6 +4049,7 @@
case 20:
switch (sel) {
case 0:
+ check_insn(env, ctx, ISA_MIPS3);
gen_op_mtc0_xcontext();
rn = "XContext";
break;
@@ -4535,8 +4605,7 @@
break;
#ifdef TARGET_MIPS64
case OPC_DMFC0:
- if (!(ctx->hflags & MIPS_HFLAG_64))
- generate_exception(ctx, EXCP_RI);
+ check_insn(env, ctx, ISA_MIPS3);
if (rt == 0) {
/* Treat as NOP. */
return;
@@ -4546,8 +4615,7 @@
opn = "dmfc0";
break;
case OPC_DMTC0:
- if (!(ctx->hflags & MIPS_HFLAG_64))
- generate_exception(ctx, EXCP_RI);
+ check_insn(env, ctx, ISA_MIPS3);
GEN_LOAD_REG_TN(T0, rt);
gen_dmtc0(env, ctx, rd, ctx->opcode & 0x7);
opn = "dmtc0";
@@ -4597,11 +4665,13 @@
break;
case OPC_ERET:
opn = "eret";
+ check_insn(env, ctx, ISA_MIPS2);
gen_op_eret();
ctx->bstate = BS_EXCP;
break;
case OPC_DERET:
opn = "deret";
+ check_insn(env, ctx, ISA_MIPS32);
if (!(ctx->hflags & MIPS_HFLAG_DM)) {
MIPS_INVAL(opn);
generate_exception(ctx, EXCP_RI);
@@ -4612,6 +4682,7 @@
break;
case OPC_WAIT:
opn = "wait";
+ check_insn(env, ctx, ISA_MIPS3 | ISA_MIPS32);
/* If we get an exception, we want to restart at next instruction */
ctx->pc += 4;
save_cpu_state(ctx, 1);
@@ -4629,12 +4700,15 @@
}
/* CP1 Branches (before delay slot) */
-static void gen_compute_branch1 (DisasContext *ctx, uint32_t op,
+static void gen_compute_branch1 (CPUState *env, DisasContext *ctx, uint32_t op,
int32_t cc, int32_t offset)
{
target_ulong btarget;
const char *opn = "cp1 cond branch";
+ if (cc != 0)
+ check_insn(env, ctx, ISA_MIPS4 | ISA_MIPS32);
+
btarget = ctx->pc + 4 + offset;
switch (op) {
@@ -5843,14 +5917,15 @@
switch (op1) {
case OPC_SLL: /* Arithmetic with immediate */
case OPC_SRL ... OPC_SRA:
- gen_arith_imm(ctx, op1, rd, rt, sa);
+ gen_arith_imm(env, ctx, op1, rd, rt, sa);
break;
+ case OPC_MOVZ ... OPC_MOVN:
+ check_insn(env, ctx, ISA_MIPS4 | ISA_MIPS32);
case OPC_SLLV: /* Arithmetic */
case OPC_SRLV ... OPC_SRAV:
- case OPC_MOVZ ... OPC_MOVN:
case OPC_ADD ... OPC_NOR:
case OPC_SLT ... OPC_SLTU:
- gen_arith(ctx, op1, rd, rs, rt);
+ gen_arith(env, ctx, op1, rd, rs, rt);
break;
case OPC_MULT ... OPC_DIVU:
gen_muldiv(ctx, op1, rs, rt);
@@ -5899,6 +5974,7 @@
break;
case OPC_MOVCI:
+ check_insn(env, ctx, ISA_MIPS4 | ISA_MIPS32);
if (env->CP0_Config1 & (1 << CP0C1_FP)) {
save_cpu_state(ctx, 1);
check_cp1_enabled(ctx);
@@ -5915,20 +5991,20 @@
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);
+ check_insn(env, ctx, ISA_MIPS3);
+ check_mips_64(ctx);
+ gen_arith_imm(env, 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);
+ check_insn(env, ctx, ISA_MIPS3);
+ check_mips_64(ctx);
+ gen_arith(env, ctx, op1, rd, rs, rt);
break;
case OPC_DMULT ... OPC_DDIVU:
- if (!(ctx->hflags & MIPS_HFLAG_64))
- generate_exception(ctx, EXCP_RI);
+ check_insn(env, ctx, ISA_MIPS3);
+ check_mips_64(ctx);
gen_muldiv(ctx, op1, rs, rt);
break;
#endif
@@ -5943,18 +6019,21 @@
switch (op1) {
case OPC_MADD ... OPC_MADDU: /* Multiply and add/sub */
case OPC_MSUB ... OPC_MSUBU:
+ check_insn(env, ctx, ISA_MIPS32);
gen_muldiv(ctx, op1, rs, rt);
break;
case OPC_MUL:
- gen_arith(ctx, op1, rd, rs, rt);
+ gen_arith(env, ctx, op1, rd, rs, rt);
break;
case OPC_CLZ ... OPC_CLO:
+ check_insn(env, ctx, ISA_MIPS32);
gen_cl(ctx, op1, rd, rs);
break;
case OPC_SDBBP:
/* XXX: not clear which exception should be raised
* when in debug mode...
*/
+ check_insn(env, ctx, ISA_MIPS32);
if (!(ctx->hflags & MIPS_HFLAG_DM)) {
generate_exception(ctx, EXCP_DBp);
} else {
@@ -5964,8 +6043,8 @@
break;
#ifdef TARGET_MIPS64
case OPC_DCLZ ... OPC_DCLO:
- if (!(ctx->hflags & MIPS_HFLAG_64))
- generate_exception(ctx, EXCP_RI);
+ check_insn(env, ctx, ISA_MIPS64);
+ check_mips_64(ctx);
gen_cl(ctx, op1, rd, rs);
break;
#endif
@@ -5976,14 +6055,15 @@
}
break;
case OPC_SPECIAL3:
- check_mips_r2(env, ctx);
op1 = MASK_SPECIAL3(ctx->opcode);
switch (op1) {
case OPC_EXT:
case OPC_INS:
+ check_insn(env, ctx, ISA_MIPS32R2);
gen_bitops(ctx, op1, rt, rs, sa, rd);
break;
case OPC_BSHFL:
+ check_insn(env, ctx, ISA_MIPS32R2);
op2 = MASK_BSHFL(ctx->opcode);
switch (op2) {
case OPC_WSBH:
@@ -6006,6 +6086,7 @@
GEN_STORE_TN_REG(rd, T0);
break;
case OPC_RDHWR:
+ check_insn(env, ctx, ISA_MIPS32R2);
switch (rd) {
case 0:
save_cpu_state(ctx, 1);
@@ -6050,13 +6131,13 @@
#ifdef TARGET_MIPS64
case OPC_DEXTM ... OPC_DEXT:
case OPC_DINSM ... OPC_DINS:
- if (!(ctx->hflags & MIPS_HFLAG_64))
- generate_exception(ctx, EXCP_RI);
+ check_insn(env, ctx, ISA_MIPS64R2);
+ check_mips_64(ctx);
gen_bitops(ctx, op1, rt, rs, sa, rd);
break;
case OPC_DBSHFL:
- if (!(ctx->hflags & MIPS_HFLAG_64))
- generate_exception(ctx, EXCP_RI);
+ check_insn(env, ctx, ISA_MIPS64R2);
+ check_mips_64(ctx);
op2 = MASK_DBSHFL(ctx->opcode);
switch (op2) {
case OPC_DSBH:
@@ -6092,7 +6173,7 @@
gen_trap(ctx, op1, rs, -1, imm);
break;
case OPC_SYNCI:
- check_mips_r2(env, ctx);
+ check_insn(env, ctx, ISA_MIPS32R2);
/* Treat as NOP. */
break;
default: /* Invalid */
@@ -6120,7 +6201,6 @@
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_DMT:
@@ -6140,11 +6220,13 @@
gen_op_evpe();
break;
case OPC_DI:
+ check_insn(env, ctx, ISA_MIPS32R2);
gen_op_di();
/* Stop translation as we may have switched the execution mode */
ctx->bstate = BS_STOP;
break;
case OPC_EI:
+ check_insn(env, ctx, ISA_MIPS32R2);
gen_op_ei();
/* Stop translation as we may have switched the execution mode */
ctx->bstate = BS_STOP;
@@ -6157,12 +6239,12 @@
GEN_STORE_TN_REG(rt, T0);
break;
case OPC_RDPGPR:
- check_mips_r2(env, ctx);
+ check_insn(env, ctx, ISA_MIPS32R2);
GEN_LOAD_SRSREG_TN(T0, rt);
GEN_STORE_TN_REG(rd, T0);
break;
case OPC_WRPGPR:
- check_mips_r2(env, ctx);
+ check_insn(env, ctx, ISA_MIPS32R2);
GEN_LOAD_REG_TN(T0, rt);
GEN_STORE_TN_SRSREG(rd, T0);
break;
@@ -6173,7 +6255,7 @@
}
break;
case OPC_ADDI ... OPC_LUI: /* Arithmetic with immediate opcode */
- gen_arith_imm(ctx, op, rt, rs, imm);
+ gen_arith_imm(env, ctx, op, rt, rs, imm);
break;
case OPC_J ... OPC_JAL: /* Jump */
offset = (int32_t)(ctx->opcode & 0x3FFFFFF) << 2;
@@ -6191,9 +6273,11 @@
gen_ldst(ctx, op, rt, rs, imm);
break;
case OPC_CACHE:
+ check_insn(env, ctx, ISA_MIPS3 | ISA_MIPS32);
/* Treat as NOP. */
break;
case OPC_PREF:
+ check_insn(env, ctx, ISA_MIPS4 | ISA_MIPS32);
/* Treat as NOP. */
break;
@@ -6219,21 +6303,24 @@
switch (op1) {
case OPC_MFHC1:
case OPC_MTHC1:
- check_mips_r2(env, ctx);
+ check_insn(env, ctx, ISA_MIPS32R2);
case OPC_MFC1:
case OPC_CFC1:
case OPC_MTC1:
case OPC_CTC1:
+ gen_cp1(ctx, op1, rt, rd);
+ break;
#ifdef TARGET_MIPS64
case OPC_DMFC1:
case OPC_DMTC1:
-#endif
+ check_insn(env, ctx, ISA_MIPS3);
gen_cp1(ctx, op1, rt, rd);
break;
+#endif
case OPC_BC1:
case OPC_BC1ANY2:
case OPC_BC1ANY4:
- gen_compute_branch1(ctx, MASK_BC1(ctx->opcode),
+ gen_compute_branch1(env, ctx, MASK_BC1(ctx->opcode),
(rt >> 2) & 0x7, imm << 2);
return;
case OPC_S_FMT:
@@ -6315,24 +6402,22 @@
case OPC_LD:
case OPC_SCD:
case OPC_SD:
- if (!(ctx->hflags & MIPS_HFLAG_64))
- generate_exception(ctx, EXCP_RI);
+ check_insn(env, ctx, ISA_MIPS3);
+ check_mips_64(ctx);
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);
+ check_insn(env, ctx, ISA_MIPS3);
+ check_mips_64(ctx);
+ gen_arith_imm(env, ctx, op, rt, rs, imm);
break;
#endif
-#ifdef MIPS_HAS_MIPS16
case OPC_JALX:
+ check_insn(env, ctx, ASE_MIPS16);
/* MIPS16: Not implemented. */
-#endif
-#ifdef MIPS_HAS_MDMX
case OPC_MDMX:
+ check_insn(env, ctx, ASE_MDMX);
/* MDMX: Not implemented. */
-#endif
default: /* Invalid */
MIPS_INVAL("major opcode");
generate_exception(ctx, EXCP_RI);
diff --git a/target-mips/translate_init.c b/target-mips/translate_init.c
index 1a98973..6bea0c4 100644
--- a/target-mips/translate_init.c
+++ b/target-mips/translate_init.c
@@ -80,6 +80,7 @@
int32_t CP0_SRSConf3;
int32_t CP0_SRSConf4_rw_bitmask;
int32_t CP0_SRSConf4;
+ int insn_flags;
};
/*****************************************************************************/
@@ -98,6 +99,7 @@
.SYNCI_Step = 32,
.CCRes = 2,
.CP0_Status_rw_bitmask = 0x1278FF17,
+ .insn_flags = CPU_MIPS32 | ASE_MIPS16,
},
{
.name = "4KEcR1",
@@ -111,6 +113,7 @@
.SYNCI_Step = 32,
.CCRes = 2,
.CP0_Status_rw_bitmask = 0x1278FF17,
+ .insn_flags = CPU_MIPS32 | ASE_MIPS16,
},
{
.name = "4KEc",
@@ -124,6 +127,7 @@
.SYNCI_Step = 32,
.CCRes = 2,
.CP0_Status_rw_bitmask = 0x1278FF17,
+ .insn_flags = CPU_MIPS32R2 | ASE_MIPS16,
},
{
.name = "24Kc",
@@ -138,6 +142,7 @@
.CCRes = 2,
/* No DSP implemented. */
.CP0_Status_rw_bitmask = 0x1278FF17,
+ .insn_flags = CPU_MIPS32R2 | ASE_MIPS16 | ASE_DSP,
},
{
.name = "24Kf",
@@ -154,6 +159,7 @@
.CP0_Status_rw_bitmask = 0x3678FF17,
.CP1_fcr0 = (1 << FCR0_F64) | (1 << FCR0_L) | (1 << FCR0_W) |
(1 << FCR0_D) | (1 << FCR0_S) | (0x93 << FCR0_PRID),
+ .insn_flags = CPU_MIPS32R2 | ASE_MIPS16 | ASE_DSP,
},
{
.name = "34Kf",
@@ -193,6 +199,7 @@
.CP0_SRSConf4_rw_bitmask = 0x3fffffff,
.CP0_SRSConf4 = (0x3fe << CP0SRSC4_SRS15) |
(0x3fe << CP0SRSC4_SRS14) | (0x3fe << CP0SRSC4_SRS13),
+ .insn_flags = CPU_MIPS32R2 | ASE_MIPS16 | ASE_DSP,
},
#ifdef TARGET_MIPS64
{
@@ -210,6 +217,7 @@
/* The R4000 has a full 64bit FPU doesn't use the fcr0 bits. */
.CP1_fcr0 = (0x5 << FCR0_PRID) | (0x0 << FCR0_REV),
.SEGBITS = 40,
+ .insn_flags = CPU_MIPS3,
},
{
.name = "5Kc",
@@ -225,6 +233,7 @@
.CCRes = 2,
.CP0_Status_rw_bitmask = 0x32F8FFFF,
.SEGBITS = 42,
+ .insn_flags = CPU_MIPS64,
},
{
.name = "5Kf",
@@ -243,6 +252,7 @@
.CP1_fcr0 = (1 << FCR0_D) | (1 << FCR0_S) |
(0x81 << FCR0_PRID) | (0x0 << FCR0_REV),
.SEGBITS = 42,
+ .insn_flags = CPU_MIPS64,
},
{
.name = "20Kc",
@@ -264,6 +274,7 @@
(1 << FCR0_D) | (1 << FCR0_S) |
(0x82 << FCR0_PRID) | (0x0 << FCR0_REV),
.SEGBITS = 40,
+ .insn_flags = CPU_MIPS64 | ASE_MIPS3D,
},
#endif
};
@@ -406,7 +417,7 @@
env->CP0_TCStatus_rw_bitmask = def->CP0_TCStatus_rw_bitmask;
env->CP0_SRSCtl = def->CP0_SRSCtl;
#ifdef TARGET_MIPS64
- if ((env->CP0_Config0 & (0x3 << CP0C0_AT)))
+ if (def->insn_flags & ISA_MIPS3)
{
env->hflags |= MIPS_HFLAG_64;
env->SEGBITS = def->SEGBITS;
@@ -426,6 +437,7 @@
env->CP0_SRSConf3 = def->CP0_SRSConf3;
env->CP0_SRSConf4_rw_bitmask = def->CP0_SRSConf4_rw_bitmask;
env->CP0_SRSConf4 = def->CP0_SRSConf4;
+ env->insn_flags = def->insn_flags;
#ifndef CONFIG_USER_ONLY
mmu_init(env, def);