From e189e7486867e36c35f99cbac27d503ce4e7c71d Mon Sep 17 00:00:00 2001 From: ths Date: Mon, 24 Sep 2007 12:48:00 +0000 Subject: Per-CPU instruction decoding implementation, by Aurelien Jarno. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3228 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/cpu.h | 1 + target-mips/helper.c | 9 +- target-mips/mips-defs.h | 35 ++++++ target-mips/op.c | 17 ++- target-mips/translate.c | 257 ++++++++++++++++++++++++++++--------------- target-mips/translate_init.c | 14 ++- 6 files changed, 230 insertions(+), 103 deletions(-) (limited to 'target-mips') diff --git a/target-mips/cpu.h b/target-mips/cpu.h index f8b4b18583..f8299ad608 100644 --- a/target-mips/cpu.h +++ b/target-mips/cpu.h @@ -441,6 +441,7 @@ struct CPUMIPSState { 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 6310d68487..d0e5b1d481 100644 --- a/target-mips/helper.c +++ b/target-mips/helper.c @@ -369,8 +369,7 @@ void do_interrupt (CPUState *env) } 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 @@ void do_interrupt (CPUState *env) 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 @@ void do_interrupt (CPUState *env) 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 6f012a964e..a796c7e096 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 8d4c7d4afd..dd90163376 100644 --- a/target-mips/op.c +++ b/target-mips/op.c @@ -1847,10 +1847,9 @@ void op_mtc0_status (void) (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 @@ void op_mtc0_cause (void) { 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 @@ void op_eret (void) (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 @@ void op_deret (void) (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 ddffc0f15d..004b2f701e 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -142,7 +142,7 @@ enum { 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 @@ void check_cp1_registers(DisasContext *ctx, int regs) } /* 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 @@ static inline void check_mips_mt(CPUState *env, DisasContext *ctx) 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 @@ static void gen_flt_ldst (DisasContext *ctx, uint32_t opc, int ft, } /* 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 @@ static void gen_arith_imm (DisasContext *ctx, uint32_t opc, int rt, 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 @@ static void gen_arith_imm (DisasContext *ctx, uint32_t opc, int rt, 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 @@ static void gen_arith_imm (DisasContext *ctx, uint32_t opc, int rt, 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 @@ static void gen_arith_imm (DisasContext *ctx, uint32_t opc, int rt, } /* 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 @@ static void gen_arith (DisasContext *ctx, uint32_t opc, 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 @@ static void gen_arith (DisasContext *ctx, uint32_t opc, 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 @@ static void gen_mfc0 (CPUState *env, DisasContext *ctx, int reg, int sel) { const char *rn = "invalid"; + if (sel != 0) + check_insn(env, ctx, ISA_MIPS32); + switch (reg) { case 0: switch (sel) { @@ -2057,7 +2098,7 @@ static void gen_mfc0 (CPUState *env, DisasContext *ctx, int reg, int sel) 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 @@ static void gen_mfc0 (CPUState *env, DisasContext *ctx, int reg, int sel) 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 @@ static void gen_mfc0 (CPUState *env, DisasContext *ctx, int reg, int sel) 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 @@ static void gen_mfc0 (CPUState *env, DisasContext *ctx, int reg, int sel) 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 @@ static void gen_mfc0 (CPUState *env, DisasContext *ctx, int reg, int sel) 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 @@ static void gen_mfc0 (CPUState *env, DisasContext *ctx, int reg, int sel) 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 @@ static void gen_mtc0 (CPUState *env, DisasContext *ctx, int reg, int sel) { const char *rn = "invalid"; + if (sel != 0) + check_insn(env, ctx, ISA_MIPS32); + switch (reg) { case 0: switch (sel) { @@ -2618,7 +2666,7 @@ static void gen_mtc0 (CPUState *env, DisasContext *ctx, int reg, int sel) 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 @@ static void gen_mtc0 (CPUState *env, DisasContext *ctx, int reg, int sel) 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 @@ static void gen_mtc0 (CPUState *env, DisasContext *ctx, int reg, int sel) 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 @@ static void gen_mtc0 (CPUState *env, DisasContext *ctx, int reg, int sel) 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 @@ static void gen_mtc0 (CPUState *env, DisasContext *ctx, int reg, int sel) 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 @@ static void gen_mtc0 (CPUState *env, DisasContext *ctx, int reg, int sel) 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 @@ static void gen_dmfc0 (CPUState *env, DisasContext *ctx, int reg, int sel) { const char *rn = "invalid"; + if (sel != 0) + check_insn(env, ctx, ISA_MIPS64); + switch (reg) { case 0: switch (sel) { @@ -3211,7 +3266,7 @@ static void gen_dmfc0 (CPUState *env, DisasContext *ctx, int reg, int sel) 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 @@ static void gen_dmfc0 (CPUState *env, DisasContext *ctx, int reg, int sel) 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 @@ static void gen_dmfc0 (CPUState *env, DisasContext *ctx, int reg, int sel) 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 @@ static void gen_dmfc0 (CPUState *env, DisasContext *ctx, int reg, int sel) 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 @@ static void gen_dmfc0 (CPUState *env, DisasContext *ctx, int reg, int sel) 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 @@ static void gen_dmfc0 (CPUState *env, DisasContext *ctx, int reg, int sel) case 20: switch (sel) { case 0: + check_insn(env, ctx, ISA_MIPS3); gen_op_dmfc0_xcontext(); rn = "XContext"; break; @@ -3612,6 +3673,9 @@ static void gen_dmtc0 (CPUState *env, DisasContext *ctx, int reg, int sel) { const char *rn = "invalid"; + if (sel != 0) + check_insn(env, ctx, ISA_MIPS64); + switch (reg) { case 0: switch (sel) { @@ -3759,7 +3823,7 @@ static void gen_dmtc0 (CPUState *env, DisasContext *ctx, int reg, int sel) 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 @@ static void gen_dmtc0 (CPUState *env, DisasContext *ctx, int reg, int sel) 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 @@ static void gen_dmtc0 (CPUState *env, DisasContext *ctx, int reg, int sel) 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 @@ static void gen_dmtc0 (CPUState *env, DisasContext *ctx, int reg, int sel) 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 @@ static void gen_dmtc0 (CPUState *env, DisasContext *ctx, int reg, int sel) 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 @@ static void gen_dmtc0 (CPUState *env, DisasContext *ctx, int reg, int sel) case 20: switch (sel) { case 0: + check_insn(env, ctx, ISA_MIPS3); gen_op_mtc0_xcontext(); rn = "XContext"; break; @@ -4535,8 +4605,7 @@ static void gen_cp0 (CPUState *env, DisasContext *ctx, uint32_t opc, int rt, int 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 @@ static void gen_cp0 (CPUState *env, DisasContext *ctx, uint32_t opc, int rt, int 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 @@ static void gen_cp0 (CPUState *env, DisasContext *ctx, uint32_t opc, int rt, int 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 @@ static void gen_cp0 (CPUState *env, DisasContext *ctx, uint32_t opc, int rt, int 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 @@ static void gen_cp0 (CPUState *env, DisasContext *ctx, uint32_t opc, int rt, int } /* 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 @@ static void decode_opc (CPUState *env, DisasContext *ctx) 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 @@ static void decode_opc (CPUState *env, DisasContext *ctx) 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 @@ 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); + 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 @@ static void decode_opc (CPUState *env, DisasContext *ctx) 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 @@ 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); + check_insn(env, ctx, ISA_MIPS64); + check_mips_64(ctx); gen_cl(ctx, op1, rd, rs); break; #endif @@ -5976,14 +6055,15 @@ static void decode_opc (CPUState *env, DisasContext *ctx) } 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 @@ static void decode_opc (CPUState *env, DisasContext *ctx) 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 @@ 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); + 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 @@ static void decode_opc (CPUState *env, DisasContext *ctx) 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 @@ static void decode_opc (CPUState *env, DisasContext *ctx) 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 @@ static void decode_opc (CPUState *env, DisasContext *ctx) 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 @@ static void decode_opc (CPUState *env, DisasContext *ctx) 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 @@ static void decode_opc (CPUState *env, DisasContext *ctx) } 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 @@ static void decode_opc (CPUState *env, DisasContext *ctx) 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 @@ static void decode_opc (CPUState *env, DisasContext *ctx) 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 @@ 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); + 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 1a98973da1..6bea0c4d12 100644 --- a/target-mips/translate_init.c +++ b/target-mips/translate_init.c @@ -80,6 +80,7 @@ struct mips_def_t { int32_t CP0_SRSConf3; int32_t CP0_SRSConf4_rw_bitmask; int32_t CP0_SRSConf4; + int insn_flags; }; /*****************************************************************************/ @@ -98,6 +99,7 @@ static mips_def_t mips_defs[] = .SYNCI_Step = 32, .CCRes = 2, .CP0_Status_rw_bitmask = 0x1278FF17, + .insn_flags = CPU_MIPS32 | ASE_MIPS16, }, { .name = "4KEcR1", @@ -111,6 +113,7 @@ static mips_def_t mips_defs[] = .SYNCI_Step = 32, .CCRes = 2, .CP0_Status_rw_bitmask = 0x1278FF17, + .insn_flags = CPU_MIPS32 | ASE_MIPS16, }, { .name = "4KEc", @@ -124,6 +127,7 @@ static mips_def_t mips_defs[] = .SYNCI_Step = 32, .CCRes = 2, .CP0_Status_rw_bitmask = 0x1278FF17, + .insn_flags = CPU_MIPS32R2 | ASE_MIPS16, }, { .name = "24Kc", @@ -138,6 +142,7 @@ static mips_def_t mips_defs[] = .CCRes = 2, /* No DSP implemented. */ .CP0_Status_rw_bitmask = 0x1278FF17, + .insn_flags = CPU_MIPS32R2 | ASE_MIPS16 | ASE_DSP, }, { .name = "24Kf", @@ -154,6 +159,7 @@ static mips_def_t mips_defs[] = .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 @@ static mips_def_t mips_defs[] = .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 @@ static mips_def_t mips_defs[] = /* 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 @@ static mips_def_t mips_defs[] = .CCRes = 2, .CP0_Status_rw_bitmask = 0x32F8FFFF, .SEGBITS = 42, + .insn_flags = CPU_MIPS64, }, { .name = "5Kf", @@ -243,6 +252,7 @@ static mips_def_t mips_defs[] = .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 @@ static mips_def_t mips_defs[] = (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 @@ int cpu_mips_register (CPUMIPSState *env, mips_def_t *def) 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 @@ int cpu_mips_register (CPUMIPSState *env, mips_def_t *def) 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); -- cgit v1.2.1